import { SyncService, SyncResult, SyncOptions } from "./types";
import { googleSearchConsole } from "./google-search-console";
import { googleAnalytics } from "./google-analytics";
import { googleBusinessProfile } from "./google-business-profile";
import { googlePageSpeed } from "./google-pagespeed";
import { bingWebmaster } from "./bing-webmaster";
import { claude } from "./claude";
import {
  getCredentials,
  saveCredentials,
  recordSyncFailure,
  recordSyncSuccess,
  removeCredentials,
} from "@/lib/services/integration-credentials";
import { log } from "@/lib/logger";

/**
 * Registry of all sync services.
 */
export const syncServices: Record<string, SyncService> = {
  gsc: googleSearchConsole,
  ga4: googleAnalytics,
  gbp: googleBusinessProfile,
  pagespeed: googlePageSpeed,
  bing: bingWebmaster,
  claude,
};

export { INTEGRATION_CATALOG, getCatalogEntry, isKeyConfigured } from "./catalog";

/**
 * Connect an integration with credential storage.
 * Wraps the service's connect() and saves any returned credentials.
 */
export async function connectIntegration(
  brandId: string,
  integrationId: string,
  credentials?: Record<string, unknown>
): Promise<SyncResult> {
  const service = syncServices[integrationId];
  if (!service) return { success: false, message: `Unknown integration: ${integrationId}` };

  try {
    const result = await service.connect(brandId, credentials);

    if (result.success && result.credentials) {
      await saveCredentials(brandId, integrationId, result.credentials);
    }

    if (result.success) {
      await recordSyncSuccess(brandId, integrationId);
    }

    log.integrationSync(service.name, result.success ? "success" : "failed", result.message);
    return result;
  } catch (err) {
    const msg = err instanceof Error ? err.message : "Connection failed";
    await recordSyncFailure(brandId, integrationId, msg);
    return { success: false, message: msg };
  }
}

/**
 * Sync an integration with stored credentials and error handling.
 * Automatically retrieves stored credentials, handles failures
 * with retry backoff, and saves refreshed tokens.
 */
export async function syncIntegration(
  brandId: string,
  integrationId: string,
  options?: SyncOptions,
): Promise<SyncResult> {
  const service = syncServices[integrationId];
  if (!service) return { success: false, message: `Unknown integration: ${integrationId}` };

  // Retrieve stored credentials
  const creds = await getCredentials(brandId, integrationId);

  try {
    const result = await service.sync(brandId, creds ?? undefined, options);

    if (result.success) {
      // Save any refreshed credentials (e.g. new access token from refresh flow)
      if (result.credentials) {
        await saveCredentials(brandId, integrationId, result.credentials);
      }
      await recordSyncSuccess(brandId, integrationId);
    } else {
      await recordSyncFailure(brandId, integrationId, result.message);
    }

    log.integrationSync(service.name, result.success ? "success" : "failed", result.message);
    return result;
  } catch (err) {
    const msg = err instanceof Error ? err.message : "Sync failed";
    await recordSyncFailure(brandId, integrationId, msg);
    log.integrationSync(service.name, "failed", msg);
    return { success: false, message: msg };
  }
}

/**
 * Disconnect an integration and remove stored credentials.
 */
export async function disconnectIntegration(
  brandId: string,
  integrationId: string
): Promise<SyncResult> {
  const service = syncServices[integrationId];
  if (!service) return { success: false, message: `Unknown integration: ${integrationId}` };

  try {
    const result = await service.disconnect(brandId);
    await removeCredentials(brandId, integrationId);
    log.integrationSync(service.name, "success", "Disconnected");
    return result;
  } catch (err) {
    const msg = err instanceof Error ? err.message : "Disconnect failed";
    return { success: false, message: msg };
  }
}

export type { SyncService, SyncResult } from "./types";
