/**
 * Provider registry + escalation.
 *
 * Default: self-hosted only. When the LLM is enabled (env + non-secret DB
 * overrides), 'assisted' mode runs self-hosted first and only escalates to the
 * LLM when critical fields are missing/low-confidence (cost trends to zero as
 * the vendor profile learns); 'only' mode uses the LLM with a self-hosted
 * fallback. The API key always comes from env, never the DB.
 */

import { selfHostedProvider } from './selfHostedProvider'
import { createLlmProvider } from './llmProvider'
import type { ExtractionInput } from './types'
import type { ExtractionResult } from '../fieldExtractors'
import { getInboxConfig, type InboxCtx } from '../inboxDb'

const CRITICAL = ['documentNo', 'issueDate', 'grandTotal']

interface LlmConfig {
  enabled: boolean
  provider: string
  baseUrl: string
  apiKey: string
  model: string
  mode: 'assisted' | 'only'
  threshold: number
}

const resolveLlmConfig = async (ctx?: InboxCtx): Promise<LlmConfig> => {
  const cfg: any = (useRuntimeConfig() as any)?.ap?.llm || {}
  // Non-secret overrides from the settings page (key stays env-only).
  let override: any = {}
  if (ctx) { try { override = (await getInboxConfig(ctx, 'llm')) || {} } catch {} }
  return {
    enabled: (override.enabled ?? cfg.enabled) === true,
    provider: override.provider || cfg.provider || 'compatible',
    baseUrl: override.baseUrl || cfg.baseUrl || '',
    apiKey: cfg.apiKey || '', // env only
    model: override.model || cfg.model || '',
    mode: (override.mode || cfg.mode || 'assisted') as 'assisted' | 'only',
    threshold: Number(override.threshold ?? cfg.threshold ?? 0.6)
  }
}

const isWeak = (r: ExtractionResult, threshold: number): boolean =>
  CRITICAL.some(k => (r.confidence?.[k] ?? 0) < threshold)

const merge = (base: ExtractionResult, extra: ExtractionResult): ExtractionResult => {
  const fields: any = { ...base.fields }
  const confidence: any = { ...base.confidence }
  for (const key of Object.keys(extra.fields || {})) {
    const ec = extra.confidence?.[key] ?? 0
    const bc = confidence[key] ?? 0
    if ((fields as any)[key] === undefined || ec > bc) {
      fields[key] = (extra.fields as any)[key]
      confidence[key] = ec
    }
  }
  return { fields, confidence, bbox: base.bbox }
}

export interface ExtractionRunResult extends ExtractionResult {
  engine: string
}

export const runExtraction = async (input: ExtractionInput, opts: { ctx?: InboxCtx } = {}): Promise<ExtractionRunResult> => {
  const selfRes = await selfHostedProvider.extract(input)
  const llm = await resolveLlmConfig(opts.ctx)

  if (!llm.enabled || !llm.baseUrl || !llm.model || (llm.provider !== 'ollama' && !llm.apiKey)) {
    return { ...selfRes, engine: 'self-hosted' }
  }

  const llmProvider = createLlmProvider(llm)

  if (llm.mode === 'only') {
    const r = await llmProvider.extract(input)
    if (Object.keys(r.fields || {}).length) return { ...r, engine: llmProvider.name }
    return { ...selfRes, engine: 'self-hosted' }
  }

  // assisted: escalate only when self-hosted is weak on critical fields
  if (isWeak(selfRes, llm.threshold)) {
    const r = await llmProvider.extract(input)
    if (Object.keys(r.fields || {}).length) {
      return { ...merge(selfRes, r), engine: `self-hosted+${llmProvider.name}` }
    }
  }
  return { ...selfRes, engine: 'self-hosted' }
}

export { selfHostedProvider }
