/**
 * Server-side helper — resolve AI keys untuk satu user.
 *
 * Urutan prioritas (cascade):
 *   1. env_vars table     — user's own encrypted keys (per-user)
 *   2. user_settings      — legacy settings (plaintext, per-user)
 *   3. global_api_keys    — admin-set global keys (encrypted, semua user)
 *   4. process.env        — server deployment env fallback
 *
 * File ini HANYA boleh diimport dari server-side code.
 */

import type { SupabaseClient } from "@supabase/supabase-js";
import { decrypt } from "@/lib/crypto";
import { ENV_VAR_KEYS } from "@/types/env-vars";
import type { EnvVar } from "@/types/env-vars";

export interface ResolvedEnvVars {
  openaiApiKey: string | null;
  anthropicApiKey: string | null;
  googleAiApiKey: string | null;
  agentRouterApiKey: string | null;
  aihubmixApiKey: string | null;
  // Fix #3: AIHubMix fallback keys — rotasi saat primary key rate-limited
  aihubmixGeminiKey: string | null;
  aihubmixFreeKeys: string[];   // ordered list: [free_1, free_2, free_3] (filter nulls)
  preferredProvider: string;
  preferredModel: string | null;
  supabaseUrl: string | null;
  supabaseAnonKey: string | null;
}

export async function resolveUserEnvVars(
  supabase: SupabaseClient,
  userId: string
): Promise<ResolvedEnvVars> {
  // Fetch all three sources in parallel
  const [envVarsRes, settingsRes, globalKeysRes] = await Promise.all([
    // 1. User-owned encrypted keys
    supabase
      .from("env_vars")
      .select("key, encrypted_value")
      .eq("user_id", userId)
      .eq("is_active", true),

    // 2. User settings (legacy plaintext)
    supabase
      .from("user_settings")
      .select(
        "openai_api_key, anthropic_api_key, google_ai_api_key, " +
        "preferred_ai_provider, preferred_model, supabase_url, supabase_anon_key"
      )
      .eq("user_id", userId)
      .single(),

    // 3. Global API keys set by admin
    supabase
      .from("global_api_keys")
      .select("key_name, encrypted_value")
      .eq("is_active", true),
  ]);

  // ── Decrypt user env_vars ────────────────────────────────────────────────────
  const userVars: Record<string, string> = {};
  if (!envVarsRes.error && envVarsRes.data) {
    for (const row of envVarsRes.data as Pick<EnvVar, "key" | "encrypted_value">[]) {
      try {
        userVars[row.key] = decrypt(row.encrypted_value);
      } catch {
        console.warn(`[env-vars] Gagal dekripsi user key: ${row.key}`);
      }
    }
  }

  // ── User settings plaintext (DEPRECATED) ───────────────────────────────────
  // API key di user_settings disimpan dalam plaintext — deprecated sejak migrasi ke env_vars.
  // Masih dibaca untuk backward-compat, tapi user harus migrasi ke /api/env-vars.
  //
  // Cast to unknown first to avoid Supabase GenericStringError type conflict.
  type UserSettingsRow = {
    openai_api_key?: string | null;
    anthropic_api_key?: string | null;
    google_ai_api_key?: string | null;
    preferred_ai_provider?: string | null;
    preferred_model?: string | null;
    supabase_url?: string | null;
    supabase_anon_key?: string | null;
  };
  const settings: UserSettingsRow | null =
    !settingsRes.error && settingsRes.data
      ? (settingsRes.data as unknown as UserSettingsRow)
      : null;

  // Warn jika masih ada legacy plaintext keys
  if (settings) {
    const legacyKeysPresent = !!(
      settings.openai_api_key ||
      settings.anthropic_api_key ||
      settings.google_ai_api_key
    );
    if (legacyKeysPresent) {
      console.warn(
        `[env-vars-resolver] User ${userId} masih menggunakan API key plaintext di user_settings. ` +
        "Migrasi ke tabel env_vars (terenkripsi) direkomendasikan."
      );
    }
  }

  // ── Decrypt global keys ─────────────────────────────────────────────────────
  const globalVars: Record<string, string> = {};
  if (!globalKeysRes.error && globalKeysRes.data) {
    for (const row of globalKeysRes.data as { key_name: string; encrypted_value: string }[]) {
      try {
        globalVars[row.key_name] = decrypt(row.encrypted_value);
      } catch {
        console.warn(`[env-vars] Gagal dekripsi global key: ${row.key_name}`);
      }
    }
  }

  /**
   * Cascade lookup:
   *   userVars[key] → settings[field] → globalVars[key] → process.env[envKey]
   */
  const get = (key: string, settingsField?: keyof UserSettingsRow, envKey?: string): string | null => {
    // 1. User's own encrypted env_vars
    if (userVars[key]) return userVars[key];
    // 2. User settings (legacy plaintext)
    if (settingsField && settings) {
      const v = settings[settingsField];
      if (v && typeof v === "string") return v;
    }
    // 3. Admin global keys
    if (globalVars[key]) return globalVars[key];
    // 4. Server process.env
    return process.env[envKey ?? key] ?? null;
  };

  // Preferred provider / model: user-level only (no global override for preferences)
  const preferredProvider =
    userVars[ENV_VAR_KEYS.PREFERRED_AI_PROVIDER] ??
    settings?.preferred_ai_provider ??
    "auto";

  const preferredModel =
    userVars[ENV_VAR_KEYS.PREFERRED_MODEL] ??
    settings?.preferred_model ??
    null;

  // Fix #3: Resolve AIHubMix fallback keys
  const aihubmixFreeKeys = [
    get(ENV_VAR_KEYS.AIHUBMIX_FREE_KEY_1, undefined, "AIHUBMIX_FREE_KEY_1"),
    get(ENV_VAR_KEYS.AIHUBMIX_FREE_KEY_2, undefined, "AIHUBMIX_FREE_KEY_2"),
    get(ENV_VAR_KEYS.AIHUBMIX_FREE_KEY_3, undefined, "AIHUBMIX_FREE_KEY_3"),
  ].filter((k): k is string => k !== null && k.length > 0);

  return {
    openaiApiKey:      get(ENV_VAR_KEYS.OPENAI_API_KEY,      "openai_api_key"),
    anthropicApiKey:   get(ENV_VAR_KEYS.ANTHROPIC_API_KEY,   "anthropic_api_key"),
    googleAiApiKey:    get(ENV_VAR_KEYS.GOOGLE_AI_API_KEY,   "google_ai_api_key"),
    agentRouterApiKey: get(ENV_VAR_KEYS.AGENTROUTER_API_KEY, undefined, "AGENTROUTER_API_KEY"),
    aihubmixApiKey:    get(ENV_VAR_KEYS.AIHUBMIX_API_KEY,    undefined, "AIHUBMIX_API_KEY"),
    aihubmixGeminiKey: get(ENV_VAR_KEYS.AIHUBMIX_GEMINI_KEY, undefined, "AIHUBMIX_GEMINI_KEY"),
    aihubmixFreeKeys,
    preferredProvider,
    preferredModel,
    supabaseUrl:       get(ENV_VAR_KEYS.SUPABASE_URL,        "supabase_url",      "NEXT_PUBLIC_SUPABASE_URL"),
    supabaseAnonKey:   get(ENV_VAR_KEYS.SUPABASE_ANON_KEY,   "supabase_anon_key", "NEXT_PUBLIC_SUPABASE_ANON_KEY"),
  };
}

export function hasAnyAiKey(vars: ResolvedEnvVars): boolean {
  return !!(
    vars.openaiApiKey ||
    vars.anthropicApiKey ||
    vars.googleAiApiKey ||
    vars.agentRouterApiKey ||
    vars.aihubmixApiKey ||
    vars.aihubmixGeminiKey ||
    vars.aihubmixFreeKeys.length > 0
  );
}

// ── Server-side cache — reduces 3 DB queries per request ─────────────────────
//
// ⚠️  PERILAKU DI VERCEL / SERVERLESS:
// Ini adalah process-level Map. Di serverless (Vercel), setiap Lambda/Worker
// instance punya memorinya sendiri dan bisa di-recycle kapan saja.
//
// Artinya:
//   - Cache TIDAK di-share antar instances (scale-out → masing-masing cold start)
//   - Cold start → cache kosong → DB query dijalankan
//   - Warm instance → cache hit → DB query tidak dijalankan
//
// Efeknya: cache berperan sebagai per-instance request coalescer,
// bukan global shared cache. Sangat berguna untuk burst traffic di satu instance,
// tapi jangan bergantung padanya sebagai penghematan DB lintas-request.
//
// Invalidasi via invalidateEnvVarsCache() hanya meng-clear cache di instance
// yang menerima request tersebut. Instance lain tetap pakai cache mereka
// sampai TTL habis (maks 5 menit).
//
// ✅ Untuk production yang butuh guaranteed real-time invalidasi lintas-instance:
//    → Gunakan Redis (Upstash) sebagai cache backend, bukan Map.
//    → Atau turunkan CACHE_TTL_MS menjadi 30-60 detik.
//
// Untuk kebanyakan use case (user ganti key lalu langsung generate),
// flow ini tetap aman karena:
//   1. User save key → invalidateEnvVarsCache di instance yang sama
//   2. Generate request (umumnya di instance yang sama setelah save) → cache miss → fresh read

const ENV_VARS_CACHE = new Map<string, { vars: ResolvedEnvVars; expiresAt: number }>();
const CACHE_TTL_MS = 5 * 60 * 1000; // 5 menit TTL — per instance, bukan global

export async function resolveUserEnvVarsCached(
  supabase: SupabaseClient,
  userId: string
): Promise<ResolvedEnvVars> {
  const cached = ENV_VARS_CACHE.get(userId);
  if (cached && Date.now() < cached.expiresAt) {
    return cached.vars;
  }
  const vars = await resolveUserEnvVars(supabase, userId);
  ENV_VARS_CACHE.set(userId, { vars, expiresAt: Date.now() + CACHE_TTL_MS });
  return vars;
}

/** Call this after the user saves/deletes API keys to force a fresh DB read. */
export function invalidateEnvVarsCache(userId: string): void {
  ENV_VARS_CACHE.delete(userId);
}
