// Pure helpers for the Coverage page (#74). Kept separate so they are unit-testable
// without rendering the server component.

export interface UseCaseRow {
  key: string
  label: string
  group: string
  regulations: string[]
  verification_methods: string[]
  mapped_controls: number
  atom_total: number
  atom_relevant: number
}

export interface CorpusDoc {
  source_regulation: string
  license_rule: number | null
  license_tier: string
  atom_count: number
  use_case: string | null
}

export interface LicenseSummaryRow {
  license_rule: number | null
  label: string
  atom_count: number
}

export interface LicenseCatalogEntry {
  source_id: string
  title: string
  publisher: string | null
  url: string | null
  version: string | null
  license_id: string | null
  license_name: string | null
  commercial_use: string | null
  ship_in_product: boolean | null
  terms_url: string | null
}

export interface CorpusOverview {
  license_summary: LicenseSummaryRow[]
  documents: CorpusDoc[]
  license_catalog: LicenseCatalogEntry[]
  totals: { documents: number; catalog_sources: number }
}

// --- Ingested legal-corpus structure (from the vector store, via the Go SDK).
// Shows WHAT each eur-lex act consists of (articles/annexes/recitals), so the
// ingested corpus is not a black box for developers. ---
export interface LegalActStructure {
  regulation_short: string
  regulation_name: string
  articles: number
  annexes: number
  recitals: number
  chunks: number
}

export interface LegalCorpus {
  regulations: LegalActStructure[]
  totals: {
    regulations: number
    articles: number
    annexes: number
    recitals: number
  }
}

// --- Korpus-Dokumente: gruppieren nach Art (Gesetz/Leitfaden/Standard/Urteil)
// + Herausgeber-Familie (DSK, EDPB, OWASP, NIST …). Deterministisch, pure. ---
interface DocCat {
  key: string
  label: string
  order: number
}
const CAT_LAW: DocCat = { key: 'law', label: 'Gesetze & Verordnungen', order: 1 }
const CAT_GUIDANCE: DocCat = {
  key: 'guidance',
  label: 'Behörden-Leitfäden & Orientierungshilfen',
  order: 2,
}
const CAT_STANDARD: DocCat = {
  key: 'standard',
  label: 'Standards & Best Practice',
  order: 3,
}
const CAT_COURT: DocCat = { key: 'court', label: 'Rechtsprechung', order: 4 }

export function categorizeCorpusDoc(src: string): { cat: DocCat; family: string } {
  const u = (src || '').toUpperCase()
  // Standards & Best Practice (technische Familien)
  if (u.includes('OWASP')) return { cat: CAT_STANDARD, family: 'OWASP' }
  if (u.includes('NIST')) return { cat: CAT_STANDARD, family: 'NIST' }
  if (u.includes('CISA')) return { cat: CAT_STANDARD, family: 'CISA' }
  if (u.includes('OECD')) return { cat: CAT_STANDARD, family: 'OECD' }
  if (u.includes('ENISA')) return { cat: CAT_STANDARD, family: 'ENISA' }
  // Behörden-Leitfäden (Datenschutz-Aufsicht + EU-Kommissions-Guides)
  if (u.startsWith('DSK'))
    return { cat: CAT_GUIDANCE, family: 'DSK (Datenschutzkonferenz)' }
  if (u.includes('EDPB')) return { cat: CAT_GUIDANCE, family: 'EDPB' }
  if (u.includes('EDPS')) return { cat: CAT_GUIDANCE, family: 'EDPS' }
  if (u.includes('WP29'))
    return { cat: CAT_GUIDANCE, family: 'WP29 (Art.-29-Gruppe)' }
  if (u.includes('BFDI')) return { cat: CAT_GUIDANCE, family: 'BfDI' }
  if (u.includes('EU MACHINERY GUIDE') || u.includes('EU BLUE GUIDE'))
    return { cat: CAT_GUIDANCE, family: 'EU-Kommission (Guides)' }
  // Rechtsprechung
  if (u.startsWith('BGH') || u.startsWith('BVGER') || u.startsWith('EUGH'))
    return { cat: CAT_COURT, family: 'Rechtsprechung' }
  // Default: Gesetz/Verordnung/Richtlinie
  return { cat: CAT_LAW, family: 'Gesetze & Verordnungen' }
}

export interface CorpusFamilyGroup {
  family: string
  total: number
  docs: CorpusDoc[]
}

export interface CorpusCatGroup {
  key: string
  label: string
  order: number
  total: number
  families: CorpusFamilyGroup[]
}

// Group corpus docs by category (ordered: laws → guidance → standards → court),
// families within each sorted by size, docs within a family by size. So all DSK
// sit together, all EDPB together, all OWASP/NIST together, under headings.
export function groupCorpusDocs(docs: CorpusDoc[]): CorpusCatGroup[] {
  const cats = new Map<string, { cat: DocCat; fam: Map<string, CorpusDoc[]> }>()
  for (const d of docs) {
    const { cat, family } = categorizeCorpusDoc(d.source_regulation)
    if (!cats.has(cat.key)) cats.set(cat.key, { cat, fam: new Map() })
    const fam = cats.get(cat.key)!.fam
    if (!fam.has(family)) fam.set(family, [])
    fam.get(family)!.push(d)
  }
  return [...cats.values()]
    .map(({ cat, fam }) => {
      const families = [...fam.entries()]
        .map(([family, ds]) => ({
          family,
          docs: [...ds].sort((a, b) => b.atom_count - a.atom_count),
          total: ds.reduce((s, d) => s + d.atom_count, 0),
        }))
        .sort((a, b) => b.total - a.total)
      return {
        key: cat.key,
        label: cat.label,
        order: cat.order,
        total: families.reduce((s, f) => s + f.total, 0),
        families,
      }
    })
    .sort((a, b) => a.order - b.order)
}

export const USE_CASE_GROUP_LABELS: Record<string, string> = {
  document: 'Dokument-Compliance',
  security: 'Security',
  cross_cutting: 'Querschnitt',
  product: 'Produkt / Sektor',
}

export function licenseTierBadgeClass(rule: number | null): string {
  switch (rule) {
    case 1:
      return 'bg-green-100 text-green-800'
    case 2:
      return 'bg-blue-100 text-blue-800'
    case 3:
      return 'bg-amber-100 text-amber-800'
    default:
      return 'bg-gray-100 text-gray-700'
  }
}

export function commercialBadgeClass(commercial: string | null): string {
  switch ((commercial || '').toLowerCase()) {
    case 'allowed':
      return 'bg-green-100 text-green-800'
    case 'restricted':
      return 'bg-amber-100 text-amber-800'
    case 'prohibited':
      return 'bg-red-100 text-red-800'
    default:
      return 'bg-gray-100 text-gray-700'
  }
}

// --- Controls drill-down (#80 Stufe-Flip + Provenance) ---

export interface ControlItem {
  id: string
  control_id?: string | null
  title: string
  objective?: string | null
  severity?: string | null
  sub_topic?: string | null
  canonical_obligation?: string | null
  source_regulation?: string | null
  source_article?: string | null
  relevant: boolean
  tier: 'core' | 'review'
  source_type: 'derived' | 'own_library'
  addressee?: string | null
  applicable: boolean
  is_gov: boolean
}

export interface ControlsResponse {
  use_case: string
  label: string
  group: string
  granularity: string
  tier: string
  total: number
  core_count: number
  review_count: number
  out_of_scope_count: number
  include_out_of_scope: boolean
  limit: number
  offset: number
  sub_topic: string | null
  subtopic_counts: Record<string, number>
  controls: ControlItem[]
}

// Addressee axis: who must fulfil an obligation. out-of-scope (authority power /
// member-state-EU / third party / meta) is advisory — hidden by default, never
// deleted. oeffentliche_stelle = additive GOV hint (public-sector customer).
export const ADDRESSEE_LABELS: Record<string, string> = {
  unternehmen: 'Unternehmen',
  oeffentliche_stelle: 'Öffentliche Stelle',
  aufsichtsbefugnis: 'Aufsichtsbehörde',
  staat_eu: 'Mitgliedstaat/EU',
  dritter: 'Dritter',
  meta: 'Meta',
}

export function addresseeLabel(a?: string | null): string {
  return a ? ADDRESSEE_LABELS[a] || a : ''
}

// Provenance line: own library vs derived-from-document (with the document, and
// article when known). The user wants to see WHERE a derived control came from.
export function provenanceLabel(
  c: Pick<ControlItem, 'source_type' | 'source_regulation' | 'source_article'>,
): string {
  if (c.source_type === 'own_library') return 'Eigene Bibliothek'
  const doc = c.source_regulation?.trim()
  if (!doc) return 'Abgeleitet'
  const art = c.source_article?.trim()
  return art ? `Abgeleitet · ${doc} ${art}` : `Abgeleitet · ${doc}`
}

export function provenanceBadgeClass(sourceType: string): string {
  return sourceType === 'own_library'
    ? 'bg-amber-100 text-amber-800'
    : 'bg-blue-100 text-blue-800'
}

export function severityBadgeClass(sev: string | null | undefined): string {
  switch ((sev || '').toLowerCase()) {
    case 'critical':
      return 'bg-red-100 text-red-800'
    case 'high':
      return 'bg-orange-100 text-orange-800'
    case 'medium':
      return 'bg-yellow-100 text-yellow-800'
    default:
      return 'bg-gray-100 text-gray-600'
  }
}

// Split into the two display tiers: Kern-Pflichten (relevant) and the
// 'zur Prüfung' tier (shown but flagged) — never hidden.
export function splitByTier(controls: ControlItem[]): {
  core: ControlItem[]
  review: ControlItem[]
} {
  const core: ControlItem[] = []
  const review: ControlItem[] = []
  for (const c of controls) (c.relevant ? core : review).push(c)
  return { core, review }
}

export interface UseCaseGroup {
  group: string
  label: string
  rows: UseCaseRow[]
}

// Group use-cases by their registry group (stable order), each group's rows
// sorted by how many relevant obligations it carries (desc).
export function groupUseCases(rows: UseCaseRow[]): UseCaseGroup[] {
  const order = ['document', 'security', 'cross_cutting', 'product']
  const by: Record<string, UseCaseRow[]> = {}
  for (const r of rows) {
    ;(by[r.group] ||= []).push(r)
  }
  const groups = order.filter((g) => by[g]?.length)
  for (const g of Object.keys(by)) {
    if (!order.includes(g)) groups.push(g)
  }
  return groups.map((g) => ({
    group: g,
    label: USE_CASE_GROUP_LABELS[g] || g,
    rows: [...by[g]].sort((a, b) => b.atom_relevant - a.atom_relevant),
  }))
}
