/**
 * Cloud-agnostic secret resolution for Node.js services + dashboards.
 *
 * Call resolveSecrets() BEFORE Zod config parsing to populate
 * process.env from a secrets provider. Falls back gracefully when unavailable.
 *
 * Provider selection via SECRETS_PROVIDER env var:
 * - 'azure-keyvault' (default if AZURE_KEYVAULT_URL is set) — Azure Key Vault
 * - 'env' (default if no vault URL) — do nothing, use .env values as-is
 *
 * Backward compatible: resolveKeyVaultSecrets() still works identically.
 */

export type SecretsProviderType = 'azure-keyvault' | 'env';

export interface SecretMapping {
  /** Provider-specific secret name (e.g. 'lysnr-cosmos-key' for AKV) */
  kvName: string;
  /** Environment variable name to populate (e.g. 'COSMOS_KEY') */
  envVar: string;
}

/**
 * Resolve which secrets provider to use.
 */
function resolveSecretsProvider(): SecretsProviderType {
  const explicit = (process.env.SECRETS_PROVIDER || '').toLowerCase();
  if (explicit === 'azure-keyvault' || explicit === 'azure') return 'azure-keyvault';
  if (explicit === 'env') return 'env';

  // Auto-detect: use AKV if AZURE_KEYVAULT_URL is set
  if (process.env.AZURE_KEYVAULT_URL) return 'azure-keyvault';
  return 'env';
}

/**
 * Cloud-agnostic secret resolution into process.env.
 *
 * - Only fetches secrets whose env var is empty/unset (env takes precedence).
 * - Skips entirely if provider is 'env' or no vault is configured.
 * - Logs warnings but does NOT throw — services fall back to .env values.
 *
 * @param secrets - Array of {kvName, envVar} mappings
 * @param opts - Optional overrides
 */
export async function resolveSecrets(
  secrets: SecretMapping[],
  opts?: { vaultUrl?: string; provider?: SecretsProviderType }
): Promise<void> {
  const provider = opts?.provider ?? resolveSecretsProvider();

  if (provider === 'env') return; // Nothing to resolve — use env vars as-is

  if (provider === 'azure-keyvault') {
    return resolveAzureKeyVaultSecrets(secrets, opts);
  }
}

/**
 * Resolve secrets from Azure Key Vault into process.env.
 * @deprecated Use resolveSecrets() instead — this is kept for backward compatibility.
 */
export async function resolveKeyVaultSecrets(
  secrets: SecretMapping[],
  opts?: { vaultUrl?: string }
): Promise<void> {
  return resolveAzureKeyVaultSecrets(secrets, opts);
}

/**
 * Azure Key Vault implementation.
 */
async function resolveAzureKeyVaultSecrets(
  secrets: SecretMapping[],
  opts?: { vaultUrl?: string }
): Promise<void> {
  const vaultUrl = opts?.vaultUrl || process.env.AZURE_KEYVAULT_URL;
  if (!vaultUrl) return; // No KV configured — use env vars as-is

  // Filter to only secrets that are missing from env
  const missing = secrets.filter(s => !process.env[s.envVar]);
  if (missing.length === 0) return; // All secrets already in env

  try {
    const { DefaultAzureCredential } = await import('@azure/identity');
    const { SecretClient } = await import('@azure/keyvault-secrets');

    const client = new SecretClient(vaultUrl, new DefaultAzureCredential());

    const results = await Promise.allSettled(
      missing.map(async s => {
        const secret = await client.getSecret(s.kvName);
        if (secret.value) {
          process.env[s.envVar] = secret.value;
        }
      })
    );

    const failures = results.filter(r => r.status === 'rejected');
    if (failures.length > 0) {
      // eslint-disable-next-line no-console -- Startup secret-resolution diagnostics must remain visible before app loggers exist.
      console.warn(
        `[secrets] ${failures.length}/${missing.length} secrets failed to resolve — falling back to env vars`
      );
    }
  } catch {
    // eslint-disable-next-line no-console -- Startup secret-resolution diagnostics must remain visible before app loggers exist.
    console.warn(`[secrets] Unable to connect to Key Vault at ${vaultUrl} — using env vars`);
  }
}

/**
 * Standard secret mappings used across all LysnrAI services.
 * Services pick the subset they need.
 */
export const LYSNR_SECRETS = {
  COSMOS_KEY: { kvName: 'lysnr-cosmos-key', envVar: 'COSMOS_KEY' },
  COSMOS_ENDPOINT: { kvName: 'lysnr-cosmos-endpoint', envVar: 'COSMOS_ENDPOINT' },
  JWT_SECRET: { kvName: 'lysnr-jwt-secret', envVar: 'JWT_SECRET' },
  STRIPE_SECRET_KEY: { kvName: 'lysnr-stripe-secret-key', envVar: 'STRIPE_SECRET_KEY' },
  STRIPE_WEBHOOK_SECRET: { kvName: 'lysnr-stripe-webhook-secret', envVar: 'STRIPE_WEBHOOK_SECRET' },
  BILLING_INTERNAL_KEY: { kvName: 'lysnr-billing-internal-key', envVar: 'BILLING_INTERNAL_KEY' },
  AZURE_BLOB_CONNECTION_STRING: {
    kvName: 'lysnr-blob-connection-string',
    envVar: 'AZURE_BLOB_CONNECTION_STRING',
  },
  AZURE_BLOB_ACCOUNT_KEY: { kvName: 'lysnr-blob-account-key', envVar: 'AZURE_BLOB_ACCOUNT_KEY' },
  GEMINI_API_KEY: { kvName: 'lysnr-gemini-api-key', envVar: 'GEMINI_API_KEY' },
  SEED_SECRET: { kvName: 'lysnr-seed-secret', envVar: 'SEED_SECRET' },
  AZURE_SPEECH_KEY: { kvName: 'lysnr-azure-speech-key', envVar: 'AZURE_SPEECH_KEY' },
  AZURE_OPENAI_KEY: { kvName: 'lysnr-azure-openai-key', envVar: 'AZURE_OPENAI_KEY' },
  AZURE_OPENAI_ENDPOINT: {
    kvName: 'lysnr-azure-openai-endpoint',
    envVar: 'AZURE_OPENAI_ENDPOINT',
  },
} as const satisfies Record<string, SecretMapping>;
