/**
 * Controls-Augmentation für den Compliance-Advisor.
 *
 * Erkennt aus der Nutzerfrage das Compliance-Thema (Use-Case) und holt die dazu
 * hinterlegten strukturierten Controls aus der geteilten Backend-API, damit der
 * Agent aus den ECHTEN Controls antworten kann — nicht nur aus RAG-Gesetzestext.
 *
 * Alles lokal: deterministische Erkennung + lokale Postgres-API + lokales Ollama.
 * KEIN externer LLM-Aufruf zur Laufzeit.
 */

const BACKEND_URL = process.env.BACKEND_API_URL || 'http://backend-compliance:8002'

export interface UseCaseLite {
  key: string
  label: string
  regulations?: string[]
  mapped_controls?: number
}

interface ControlLite {
  control_id?: string
  master_control_id?: string
  title: string
  sub_topic?: string | null
  source_regulation?: string | null
  primary_regulation?: string | null
}

interface ControlsResponse {
  total?: number
  granularity?: string
  controls?: ControlLite[]
}

function norm(s: string): string {
  return s.toLowerCase().replace(/[^a-z0-9äöüß ]+/g, ' ')
}

/**
 * Deterministische Themen-Erkennung (pure → testbar). Punktet Key-Phrase (3),
 * Label-Wort exakt/Präfix (2) und Quell-Regulierung (1); Schwelle >=2.
 * Gleichstand → das stärker befüllte Thema.
 */
export function detectUseCase(
  message: string,
  useCases: UseCaseLite[],
): UseCaseLite | null {
  const full = norm(message)
  const words = new Set(full.split(/\s+/).filter((w) => w.length >= 3))
  let best: { uc: UseCaseLite; score: number } | null = null

  for (const uc of useCases) {
    let score = 0
    if (full.includes(uc.key.replace(/_/g, ' '))) score += 3
    for (const lw of norm(uc.label).split(/\s+/)) {
      if (lw.length < 4) continue
      for (const mw of words) {
        if (mw === lw) { score += 2; break }
        if (mw.length >= 5 && lw.length >= 5 && (mw.startsWith(lw) || lw.startsWith(mw))) {
          score += 2
          break
        }
      }
    }
    for (const r of uc.regulations || []) {
      if (r.length >= 3 && full.includes(r.toLowerCase())) score += 1
    }
    const better =
      !best ||
      score > best.score ||
      (score === best.score &&
        (uc.mapped_controls || 0) > (best.uc.mapped_controls || 0))
    if (score >= 2 && better) best = { uc, score }
  }
  return best ? best.uc : null
}

async function getJson<T>(path: string): Promise<T | null> {
  try {
    const res = await fetch(`${BACKEND_URL}${path}`, {
      signal: AbortSignal.timeout(8000),
    })
    if (!res.ok) return null
    return (await res.json()) as T
  } catch {
    return null
  }
}

/**
 * Baut den Controls-Kontext-Block für den System-Prompt — oder '' wenn kein
 * Thema erkannt wird bzw. das Backend nicht erreichbar ist (graceful degradation
 * → der Agent fällt auf RAG-only zurück).
 */
export async function buildControlsContext(message: string): Promise<string> {
  const useCases = await getJson<UseCaseLite[]>('/api/compliance/v1/controls/use-cases')
  if (!useCases || !Array.isArray(useCases)) return ''

  const uc = detectUseCase(message, useCases)
  if (!uc) return ''

  const data = await getJson<ControlsResponse>(
    `/api/compliance/v1/controls/use-cases/${encodeURIComponent(uc.key)}/controls?limit=15`,
  )
  const controls = data?.controls ?? []
  if (!controls.length) return ''
  const total = data?.total ?? controls.length

  const lines = controls.map((c, i) => {
    const cid = c.control_id || c.master_control_id || '?'
    const sub = c.sub_topic ? ` · ${c.sub_topic}` : ''
    const src = c.source_regulation || c.primary_regulation
    const reg = src ? ` — Quelle: ${src}` : ''
    return `${i + 1}. [${cid}]${sub} ${c.title}${reg}`
  })

  return `## Strukturierte Controls aus der Datenbank — Thema: ${uc.label}

Die folgenden ${controls.length} von insgesamt ${total} hinterlegten Controls zu diesem Thema kommen direkt aus der Control-Datenbank (nach Relevanz sortiert). Nutze sie als verbindliche Quelle für konkrete Prüfaspekte/Pflichten und verweise auf die Control-ID. Erfinde KEINE Control-IDs; wirkt die Liste unvollständig, sage das offen.

${lines.join('\n')}`
}
