import logger from '../common/utils/logger.js';
import {
  googleSecretManager,
  initializeSmtpSecretsFromGoogle,
} from './googleSecretManager.service.js';

export interface SmtpConfig {
  /** Whether outbound SMTP is allowed (ENABLE_SMTP=true) */
  enabled: boolean;
  host: string;
  port: number;
  secure: boolean;
  auth: {
    user: string;
    pass: string;
  };
  from: string;
  /** Where values were resolved from */
  source: 'disabled' | 'env' | 'secret-manager' | 'mixed';
}

let cachedConfig: SmtpConfig | null = null;
let initialized = false;

function envFlagTrue(name: string, defaultWhenUnset = false): boolean {
  const raw = process.env[name];
  if (raw === undefined || raw === '') return defaultWhenUnset;
  return raw === 'true' || raw === '1';
}

/** Toggle real SMTP usage (set false in local dev). */
export function isSmtpEnabled(): boolean {
  return envFlagTrue('ENABLE_SMTP', false);
}

function readEnv(key: string): string | undefined {
  const v = process.env[key];
  return v !== undefined && v !== '' ? v : undefined;
}

/** Prefer EMAIL_* (.env.example), fall back to SMTP_* after GSM load */
function pickEnv(...keys: string[]): string | undefined {
  for (const key of keys) {
    const v = readEnv(key);
    if (v !== undefined) return v;
  }
  return undefined;
}

function parsePort(value: string | undefined, fallback: number): number {
  if (!value) return fallback;
  const n = Number.parseInt(value, 10);
  return Number.isFinite(n) ? n : fallback;
}

function parseSecure(port: number, explicit?: string): boolean {
  if (explicit !== undefined) {
    return explicit === 'true' || explicit === '1';
  }
  return port === 465;
}

function buildConfigFromEnv(source: SmtpConfig['source']): SmtpConfig {
  const enabled = isSmtpEnabled();
  const host = pickEnv('EMAIL_HOST', 'SMTP_HOST') || 'smtp.gmail.com';
  const port = parsePort(pickEnv('EMAIL_PORT', 'SMTP_PORT'), 587);
  const secureRaw = pickEnv('EMAIL_SECURE', 'SMTP_SECURE');
  const secure = parseSecure(port, secureRaw);
  const user = pickEnv('EMAIL_USER', 'SMTP_USER') || '';
  const pass = pickEnv('EMAIL_PASSWORD', 'SMTP_PASSWORD') || '';
  const from =
    pickEnv('EMAIL_FROM', 'SMTP_FROM') || 'Royal Enfield <noreply@royalenfield.com>';

  return {
    enabled,
    host,
    port,
    secure,
    auth: { user, pass },
    from,
    source,
  };
}

function validateConfig(config: SmtpConfig): void {
  if (!config.enabled) {
    logger.info('[SMTP] Disabled via ENABLE_SMTP — email sending should use mocks or skip SMTP');
    return;
  }

  const missing: string[] = [];
  if (!config.host) missing.push('EMAIL_HOST / SMTP_HOST');
  if (!config.auth.user) missing.push('EMAIL_USER / SMTP_USER');
  if (!config.auth.pass) missing.push('EMAIL_PASSWORD / SMTP_PASSWORD');

  if (missing.length > 0) {
    logger.warn(`[SMTP] Enabled but missing: ${missing.join(', ')}`);
  } else {
    logger.info('[SMTP] ─── Resolved config ───');
    logger.info(`[SMTP]   source: ${config.source}`);
    logger.info(`[SMTP]   host: ${config.host}`);
    logger.info(`[SMTP]   port: ${config.port}`);
    logger.info(`[SMTP]   secure: ${config.secure}`);
    logger.info(`[SMTP]   user: ${config.auth.user || '(empty)'}`);
    logger.info(
      `[SMTP]   password: ${config.auth.pass ? `*** (${config.auth.pass.length} chars)` : '(empty)'}`
    );
    logger.info(`[SMTP]   from: ${config.from}`);
    logger.info('[SMTP] ─── Ready ───');
  }
}

/**
 * Load SMTP settings: optional Google Secret Manager → merge into env → build config.
 * Call once during server startup.
 */
export async function initializeSmtpConfig(): Promise<SmtpConfig> {
  if (initialized && cachedConfig) {
    return cachedConfig;
  }

  let source: SmtpConfig['source'] = 'env';

  logger.info('[SMTP] ─── Initializing SMTP config ───');
  logger.info(`[SMTP] ENABLE_SMTP=${process.env.ENABLE_SMTP ?? '(unset)'} → ${isSmtpEnabled() ? 'enabled' : 'disabled'}`);
  logger.info(
    `[SMTP] USE_GOOGLE_SECRET_MANAGER=${process.env.USE_GOOGLE_SECRET_MANAGER ?? '(unset)'}`
  );

  if (googleSecretManager.isEnabled()) {
    logger.info('[SMTP] Loading SMTP secrets from Google Secret Manager...');
    const loaded = await initializeSmtpSecretsFromGoogle();
    source = Object.keys(loaded).length > 0 ? 'secret-manager' : 'env';

    if (Object.keys(loaded).length > 0) {
      logger.info(`[SMTP] GSM returned ${Object.keys(loaded).length} value(s):`);
      for (const [envVar, value] of Object.entries(loaded)) {
        const masked =
          /PASSWORD|SECRET/i.test(envVar) ? `*** (${value.length} chars)` : value;
        logger.info(`[SMTP]   • ${envVar} = ${masked}`);
      }
    } else {
      logger.warn('[SMTP] No secrets returned from GSM — will use .env if present');
    }

    const hasLocal =
      Boolean(readEnv('EMAIL_HOST') || readEnv('SMTP_HOST')) &&
      Boolean(readEnv('EMAIL_USER') || readEnv('SMTP_USER'));
    if (Object.keys(loaded).length > 0 && hasLocal) {
      source = 'mixed';
      logger.info('[SMTP] Config source: mixed (GSM + local .env)');
    }
  } else {
    logger.info('[SMTP] Google Secret Manager disabled — using .env only');
  }

  if (!isSmtpEnabled()) {
    cachedConfig = {
      ...buildConfigFromEnv('disabled'),
      enabled: false,
      source: 'disabled',
    };
    initialized = true;
    validateConfig(cachedConfig);
    return cachedConfig;
  }

  cachedConfig = buildConfigFromEnv(source);
  initialized = true;
  validateConfig(cachedConfig);
  return cachedConfig;
}

/** Resolved SMTP config (call after initializeSmtpConfig). */
export function getSmtpConfig(): SmtpConfig {
  if (!cachedConfig) {
    return buildConfigFromEnv('env');
  }
  return cachedConfig;
}

/** Nodemailer-compatible transport options */
export function getNodemailerTransportOptions(): {
  host: string;
  port: number;
  secure: boolean;
  auth: { user: string; pass: string };
} | null {
  const config = getSmtpConfig();
  if (!config.enabled) return null;
  if (!config.auth.user || !config.auth.pass) return null;

  return {
    host: config.host,
    port: config.port,
    secure: config.secure,
    auth: config.auth,
  };
}

export function resetSmtpConfigForTests(): void {
  cachedConfig = null;
  initialized = false;
}
