import { eq } from 'drizzle-orm';
import type { DrizzleClient } from '../client.js';
import { systemConfig } from '../schema.js';

type Db = DrizzleClient;

/** Well-known config keys. Extend as new settings are added. */
export type SystemConfigKey =
  | 'llm_model'
  | 'llm_fallback_model'
  | 'llm_moderation_prompt'
  | 'llm_sla_hours'
  | 'deal_min_discount_percent'
  | 'deal_hot_threshold'
  | 'google_api_key'
  // Support system (phase 1)
  | 'support_vendor_window_hours'
  | 'support_sla_ai_hours'
  | 'support_sla_human_hours'
  | 'support_autoclose_days'
  | 'support_auto_refund_cap_cents'
  | 'support_ai_confidence_threshold'
  | 'support_ai_max_tool_calls'
  | 'support_ai_max_cost_cents'
  | 'support_notification_emails'
  | 'support_media_max_images'
  | 'support_media_max_mb'
  | 'support_return_window_days'
  | 'support_reopen_limit'
  | 'support_llm_triage_model'
  | 'support_llm_decision_model'
  // Translation engine (plan-2)
  | 'translation_model_id'
  | 'translation_model_input_usd_per_mtok'
  | 'translation_model_output_usd_per_mtok'
  | 'translation_daily_budget_usd'
  | 'translation_daily_spent_usd'
  | 'translation_tm_ttl_days'
  | 'translation_health_ok'
  | 'translation_health_checked_at'
  | 'translation_price_usd_per_kchar'
  // Physical delivery + settlement hold (item delivery feature)
  | 'settlement.hold_business_days'
  | 'delivery.default_carrier'
  | 'delivery.free_shipping_threshold_agorot'
  | 'delivery.max_weight_grams'
  | 'item.max_physical_qty_per_order'
  | 'item.address_cache_ttl_days'
  // AI job runner — per-job-type provider/model, per-provider API key
  | `provider:${'DEAL_MODERATION' | 'IMAGE_APPROVAL' | 'REVIEW_PRESCORING' | 'TRANSLATION' | 'VENDOR_VIOLATION'}`
  | `model:${'DEAL_MODERATION' | 'IMAGE_APPROVAL' | 'REVIEW_PRESCORING' | 'TRANSLATION' | 'VENDOR_VIOLATION'}`
  // Israeli VAT schedule
  | 'il.vat_schedule'
  | `apikey:${'gemini' | 'openai' | 'anthropic'}`;

/** Default values for each key - used when the row is absent from DB. */
const CONFIG_DEFAULTS: Partial<Record<SystemConfigKey, string>> = {
  llm_sla_hours: '4',
  deal_min_discount_percent: '0',
  deal_hot_threshold: '10',
  support_vendor_window_hours: '48',
  support_sla_ai_hours: '2',
  support_sla_human_hours: '24',
  support_autoclose_days: '7',
  support_auto_refund_cap_cents: '5000',
  support_ai_confidence_threshold: '0.8',
  support_ai_max_tool_calls: '12',
  support_ai_max_cost_cents: '50',
  support_notification_emails: '[]',
  support_media_max_images: '10',
  support_media_max_mb: '10',
  support_return_window_days: '30',
  support_reopen_limit: '2',
  support_llm_triage_model: '',
  support_llm_decision_model: '',
  'settlement.hold_business_days': '7',
  'delivery.default_carrier': 'israel_post',
  'delivery.free_shipping_threshold_agorot': '29900',
  'item.max_physical_qty_per_order': '10',
  'item.address_cache_ttl_days': '30',
};

// ── Read-hot cache ────────────────────────────────────────────────────────
// Isolate-local memo for keys read on every request. Setter invalidates the
// matching local entry. Admin saves from another isolate are stale up to TTL —
// tolerable for these keys (admin saves are rare and convergence is bounded).
const CACHE_TTL_MS = 60_000;
const _cache = new Map<SystemConfigKey, { value: string; expiresAt: number }>();

export async function getSystemConfigCached(
  db: Db,
  key: SystemConfigKey,
  ttlMs: number = CACHE_TTL_MS,
): Promise<string> {
  const now = Date.now();
  const hit = _cache.get(key);
  if (hit && hit.expiresAt > now) return hit.value;
  const value = await getSystemConfig(db, key);
  _cache.set(key, { value, expiresAt: now + ttlMs });
  return value;
}

export async function getSystemConfig(db: Db, key: SystemConfigKey): Promise<string> {
  const rows = await db
    .select({ value: systemConfig.value })
    .from(systemConfig)
    .where(eq(systemConfig.key, key))
    .limit(1);
  return rows[0]?.value ?? CONFIG_DEFAULTS[key] ?? '';
}

export async function setSystemConfig(
  db: Db,
  key: SystemConfigKey,
  value: string,
  updatedBy?: string,
): Promise<void> {
  await db
    .insert(systemConfig)
    .values({ key, value, updatedBy: updatedBy ?? null })
    .onConflictDoUpdate({
      target: systemConfig.key,
      set: {
        value,
        updatedAt: new Date(),
        updatedBy: updatedBy ?? null,
      },
    });
  _cache.delete(key); // local invalidation — see CACHE_TTL_MS note
}

export async function insertSystemConfigIfMissing(
  db: Db,
  key: string,
  value: string,
  updatedBy?: string,
): Promise<void> {
  await db
    .insert(systemConfig)
    .values({ key, value, updatedBy: updatedBy ?? null })
    .onConflictDoNothing();
}

export async function getAllSystemConfig(db: Db): Promise<Record<string, string>> {
  const rows = await db
    .select({ key: systemConfig.key, value: systemConfig.value })
    .from(systemConfig);
  const result: Record<string, string> = { ...(CONFIG_DEFAULTS as Record<string, string>) };
  for (const row of rows) {
    result[row.key] = row.value;
  }
  return result;
}
