/**
 * Google Ads Auth Service
 *
 * Platform-wide Google Ads API credential management for Super Admin → Settings.
 * This service handles credential CRUD (get/save/delete) for the Google Ads API
 * integration, following the same pattern as Pinterest/Twitter/Threads auth services.
 *
 * Credentials are AES-256-GCM encrypted at rest. The Developer Token and Client
 * Secret are never echoed back to the browser — only masked versions and boolean
 * flags indicate whether they exist.
 *
 * Environment variable fallback is supported: if no DB config exists, the service
 * falls back to GOOGLE_ADS_DEVELOPER_TOKEN, GOOGLE_ADS_CLIENT_ID, etc.
 */

import { encryptApiKey, decryptApiKey } from '../utils/encryption';

// ============================================
// CONFIGURATION
// ============================================

const ENV_DEVELOPER_TOKEN = process.env.GOOGLE_ADS_DEVELOPER_TOKEN || '';
const ENV_CLIENT_ID = process.env.GOOGLE_ADS_CLIENT_ID || '';
const ENV_CLIENT_SECRET = process.env.GOOGLE_ADS_CLIENT_SECRET || '';
const ENV_REDIRECT_URI = process.env.GOOGLE_ADS_REDIRECT_URI || 'https://yourdomain.com/api/ads/google/callback';
const ENV_MANAGER_ID = process.env.GOOGLE_ADS_MANAGER_ID || '';

const PLATFORM_CONFIG_KEY = 'platform';

// ============================================
// CREDENTIAL RESOLUTION (super-admin saved config first, env fallback)
// ============================================

export interface GoogleAdsCredentials {
  developerToken: string;
  clientId: string;
  clientSecret: string;
  redirectUrl: string;
  managerId: string;
  source: 'platform' | 'env';
}

export async function getGoogleAdsCredentials(): Promise<GoogleAdsCredentials | null> {
  try {
    const { getModels } = await import('../../models');
    const { GoogleAdsAppConfig } = getModels();

    const config = await GoogleAdsAppConfig.findOne({ companyId: PLATFORM_CONFIG_KEY })
      .select('+encryptedDeveloperToken +developerTokenIV +encryptedClientId +clientIdIV +encryptedClientSecret +clientSecretIV')
      || await GoogleAdsAppConfig.findOne({})
        .sort({ updatedAt: -1 })
        .select('+encryptedDeveloperToken +developerTokenIV +encryptedClientId +clientIdIV +encryptedClientSecret +clientSecretIV');

    if (config?.encryptedDeveloperToken && config?.developerTokenIV && config?.encryptedClientId && config?.clientIdIV && config?.encryptedClientSecret && config?.clientSecretIV) {
      return {
        developerToken: decryptApiKey(config.encryptedDeveloperToken, config.developerTokenIV),
        clientId: decryptApiKey(config.encryptedClientId, config.clientIdIV),
        clientSecret: decryptApiKey(config.encryptedClientSecret, config.clientSecretIV),
        redirectUrl: config.redirectUrl || ENV_REDIRECT_URI,
        managerId: config.managerId || '',
        source: 'platform',
      };
    }
  } catch (error) {
    console.error('Failed to load platform Google Ads credentials:', error);
  }

  if (ENV_DEVELOPER_TOKEN && ENV_CLIENT_ID && ENV_CLIENT_SECRET) {
    return {
      developerToken: ENV_DEVELOPER_TOKEN,
      clientId: ENV_CLIENT_ID,
      clientSecret: ENV_CLIENT_SECRET,
      redirectUrl: ENV_REDIRECT_URI,
      managerId: ENV_MANAGER_ID,
      source: 'env',
    };
  }

  return null;
}

export async function saveGoogleAdsCredentials(
  userId: string,
  input: { developerToken: string; clientId: string; clientSecret: string; redirectUrl?: string; managerId?: string }
): Promise<{ success: boolean; error?: string }> {
  const developerToken = (input.developerToken || '').trim();
  const clientId = (input.clientId || '').trim();
  const clientSecret = (input.clientSecret || '').trim();
  const redirectUrl = (input.redirectUrl || '').trim() || ENV_REDIRECT_URI;
  const managerId = (input.managerId || '').trim();

  if (!developerToken) {
    return { success: false, error: 'Developer Token is required' };
  }
  if (!clientId) {
    return { success: false, error: 'Client ID is required' };
  }

  try {
    new URL(redirectUrl);
  } catch {
    return { success: false, error: 'Redirect URI must be a valid URL' };
  }

  const { getModels } = await import('../../models');
  const { GoogleAdsAppConfig } = getModels();

  // The Client Secret is write-only — it is never returned to the browser, so
  // the Edit form leaves it blank when the admin isn't changing it. In that case
  // keep the existing encrypted secret instead of wiping it. A new secret is only
  // required when none exists yet (first-time setup).
  const existing = await GoogleAdsAppConfig.findOne({ companyId: PLATFORM_CONFIG_KEY })
    .select('+encryptedClientSecret +clientSecretIV');

  let encryptedSecretValue: string;
  let clientSecretIVValue: string;
  if (clientSecret) {
    const enc = encryptApiKey(clientSecret);
    encryptedSecretValue = enc.encrypted;
    clientSecretIVValue = enc.iv;
  } else if (existing?.encryptedClientSecret && existing?.clientSecretIV) {
    encryptedSecretValue = existing.encryptedClientSecret;
    clientSecretIVValue = existing.clientSecretIV;
  } else {
    return { success: false, error: 'Client Secret is required' };
  }

  const encryptedDevToken = encryptApiKey(developerToken);
  const encryptedId = encryptApiKey(clientId);

  await GoogleAdsAppConfig.deleteMany({});
  await GoogleAdsAppConfig.create({
    companyId: PLATFORM_CONFIG_KEY,
    encryptedDeveloperToken: encryptedDevToken.encrypted,
    developerTokenIV: encryptedDevToken.iv,
    encryptedClientId: encryptedId.encrypted,
    clientIdIV: encryptedId.iv,
    encryptedClientSecret: encryptedSecretValue,
    clientSecretIV: clientSecretIVValue,
    redirectUrl,
    managerId,
    updatedBy: userId,
  });

  return { success: true };
}

export async function deleteGoogleAdsCredentials(): Promise<void> {
  const { getModels } = await import('../../models');
  const { GoogleAdsAppConfig } = getModels();
  await GoogleAdsAppConfig.deleteMany({});
}

export async function getCredentialStatus(): Promise<{
  configured: boolean;
  source: 'platform' | 'env' | null;
  developerTokenMasked?: string;
  clientId?: string;
  clientIdMasked?: string;
  hasClientSecret?: boolean;
  redirectUrl: string;
  managerId: string;
}> {
  const credentials = await getGoogleAdsCredentials();
  if (!credentials) {
    return { configured: false, source: null, redirectUrl: ENV_REDIRECT_URI, managerId: '' };
  }
  return {
    configured: true,
    source: credentials.source,
    developerTokenMasked: `${credentials.developerToken.slice(0, 4)}…${credentials.developerToken.slice(-4)}`,
    clientId: credentials.clientId,
    clientIdMasked: `${credentials.clientId.slice(0, 4)}…${credentials.clientId.slice(-4)}`,
    hasClientSecret: !!credentials.clientSecret,
    redirectUrl: credentials.redirectUrl,
    managerId: credentials.managerId,
  };
}