import {
  getProviderConnections,
  getModelAliases,
  getCombos,
  getApiKeys,
  updateProviderConnection,
} from "@/lib/localDb";

const CLOUD_URL = process.env.CLOUD_URL || process.env.NEXT_PUBLIC_CLOUD_URL;
const CLOUD_SYNC_TIMEOUT_MS = Number(process.env.CLOUD_SYNC_TIMEOUT_MS || 12000);

export async function fetchWithTimeout(url, options = {}, timeoutMs = CLOUD_SYNC_TIMEOUT_MS) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
  try {
    return await fetch(url, { ...options, signal: controller.signal });
  } finally {
    clearTimeout(timeoutId);
  }
}

/**
 * Sync data to Cloud (shared utility)
 * @param {string} machineId
 * @param {string|null} createdKey - Key created during enable
 */
export async function syncToCloud(machineId, createdKey = null) {
  if (!CLOUD_URL) {
    return { error: "NEXT_PUBLIC_CLOUD_URL is not configured" };
  }

  // Get current data from db
  const providers = await getProviderConnections();
  const modelAliases = await getModelAliases();
  const combos = await getCombos();
  const apiKeys = await getApiKeys();

  let response;
  try {
    // Send to Cloud
    response = await fetchWithTimeout(`${CLOUD_URL}/sync/${machineId}`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        providers,
        modelAliases,
        combos,
        apiKeys,
      }),
    });
  } catch (error) {
    const isTimeout = error?.name === "AbortError";
    return { error: isTimeout ? "Cloud sync timeout" : "Cloud sync request failed" };
  }

  if (!response.ok) {
    const errorText = await response.text();
    const truncated = errorText.length > 200 ? errorText.slice(0, 200) + "…" : errorText;
    console.log(`Cloud sync failed (${response.status}):`, truncated);
    return { error: "Cloud sync failed" };
  }

  const result = await response.json();

  // Update local db with tokens from Cloud (providers stored by ID)
  if (result.data && result.data.providers) {
    await updateLocalTokens(result.data.providers);
  }

  const responseData: any = {
    success: true,
    message: "Synced successfully",
    changes: result.changes,
  };

  if (createdKey) {
    responseData.createdKey = createdKey;
  }

  return responseData;
}

/**
 * Update local db with data from Cloud
 * Simple logic: if Cloud is newer, sync entire provider
 * cloudProviders is object keyed by provider ID
 */
async function updateLocalTokens(cloudProviders) {
  const localProviders = await getProviderConnections();

  for (const localProvider of localProviders) {
    const cloudProvider = cloudProviders[localProvider.id];
    if (!cloudProvider) continue;

    const cloudUpdatedAt = new Date(cloudProvider.updatedAt || 0).getTime();
    const localUpdatedAt = new Date(localProvider.updatedAt || 0).getTime();

    // Simple logic: if Cloud is newer, sync entire provider
    if (cloudUpdatedAt > localUpdatedAt) {
      const updates = {
        // Tokens
        accessToken: cloudProvider.accessToken,
        refreshToken: cloudProvider.refreshToken,
        expiresAt: cloudProvider.expiresAt,
        expiresIn: cloudProvider.expiresIn,

        // Provider specific data
        providerSpecificData:
          cloudProvider.providerSpecificData || localProvider.providerSpecificData,

        // Status fields
        testStatus: cloudProvider.status || "active",
        lastError: cloudProvider.lastError,
        lastErrorAt: cloudProvider.lastErrorAt,
        errorCode: cloudProvider.errorCode,
        rateLimitedUntil: cloudProvider.rateLimitedUntil,

        // Metadata
        updatedAt: cloudProvider.updatedAt,
      };

      await updateProviderConnection(localProvider.id, updates);
    }
  }
}

export { CLOUD_URL, CLOUD_SYNC_TIMEOUT_MS };
