// Confidence-/Provenance-UI read-model helpers (KAR-911/P4.1).
//
// Problem this module closes: material-parser.ts / sbm-parser.ts /
// rmr-parser.ts / logistics-parser.ts / lccn-parser.ts / co2e-parser.ts each
// already compute + persist a `coreFieldsFound` flag on `qaf_file.g60_meta`
// (see actions.ts's g60_meta insert — materialMeta/sbmMeta/rmrMeta/
// logisticsMeta/lccnMeta/co2eMeta) whenever a detail sheet is PRESENT in the
// workbook but too degraded to trust (header row unreadable/renamed beyond
// the confidence floor). That signal was never surfaced anywhere in the UI —
// a degraded detail sheet looked identical to a QAF that simply never had
// that sheet at all (silently nothing, Master-Prompt §16 "Do not hide
// uncertainty behind a single green status").
//
// This module does NOT compute any new confidence/validation — every
// `coreFieldsFound` boolean it reads was already decided by the respective
// parser. It only decides how to LABEL/GROUP that already-persisted signal
// for a UI read-model (qaf-comparison-detail.tsx via
// app/qaf-differences/[id]/page.tsx). Pure, no I/O, test-driven — see
// __tests__/module-degradation.test.ts.

export interface DegradedModule {
  /** Stable UI key — also useful as a React list key. */
  key: string
  labelDe: string
  labelEn: string
}

interface ModuleParseMetaLike {
  coreFieldsFound?: boolean
}

/**
 * Structural subset of `qaf_file.g60_meta` this module reads. The real JSONB
 * carries far more (rows, templateFingerprint, workbookSafety, ...) — see
 * actions.ts's g60_meta insert for the full shape. Deliberately loose/
 * duck-typed rather than importing every parser's Persisted*Meta type: this
 * module only ever touches `coreFieldsFound`, never the row payloads.
 */
export interface DegradationMetaInput {
  material?: { parseMeta?: ModuleParseMetaLike } | null
  sbm?: { parseMeta?: ModuleParseMetaLike } | null
  rmr?: { parseMeta?: ModuleParseMetaLike } | null
  logistics?: { parseMeta?: ModuleParseMetaLike } | null
  /** LC-CN persists as the LccnParseResult itself (single-record parser, no
   * `rows` array) — its meta lives at `.meta`, not `.parseMeta` (see
   * actions.ts: `const lccnMeta: PersistedLccnMeta | null = lccnParsed`). */
  lccn?: { meta?: ModuleParseMetaLike } | null
  /** CO2e persists two independent facets (summary + material rows) — only
   * the material facet is checked here (mirrors co2eMaterialRowsForReconciliation's
   * tri-state, the one other engine module already treats degradation-worthy;
   * the summary facet's own values/sourceCells are single scalars, not a
   * detail-sheet the UI renders rows for). */
  co2e?: { material?: { parseMeta?: ModuleParseMetaLike } | null } | null
}

const MODULE_ORDER: ReadonlyArray<{
  pick: (meta: DegradationMetaInput) => ModuleParseMetaLike | undefined
  key: string
  labelDe: string
  labelEn: string
}> = [
  { pick: (m) => m.material?.parseMeta, key: 'material', labelDe: 'MATERIAL', labelEn: 'MATERIAL' },
  { pick: (m) => m.sbm?.parseMeta, key: 'sbm', labelDe: 'SBM-DEVICES-FWZ', labelEn: 'SBM-DEVICES-FWZ' },
  { pick: (m) => m.rmr?.parseMeta, key: 'rmr', labelDe: 'RAW MATERIAL RISKS', labelEn: 'RAW MATERIAL RISKS' },
  { pick: (m) => m.logistics?.parseMeta, key: 'logistics', labelDe: 'LOGISTICS & CUSTOM', labelEn: 'LOGISTICS & CUSTOM' },
  { pick: (m) => m.lccn?.meta, key: 'lccn', labelDe: 'LC-CN', labelEn: 'LC-CN' },
  {
    pick: (m) => m.co2e?.material?.parseMeta,
    key: 'co2e_material',
    labelDe: 'Carbon Footprint (Material)',
    labelEn: 'Carbon Footprint (material)',
  },
]

/**
 * Modules whose detail sheet was PRESENT in the workbook but too degraded to
 * parse (`coreFieldsFound === false`). A module whose meta is entirely
 * absent (the file never had that sheet — the normal case for most QAFs) is
 * NOT included: that is a structural "not applicable", not a degradation
 * (mirrors the qaf-section-registry.ts placeholder convention: absent ≠
 * broken).
 */
export function extractDegradedModules(meta: DegradationMetaInput | null | undefined): DegradedModule[] {
  if (!meta) return []
  const out: DegradedModule[] = []
  for (const m of MODULE_ORDER) {
    const parseMeta = m.pick(meta)
    if (parseMeta && parseMeta.coreFieldsFound === false) {
      out.push({ key: m.key, labelDe: m.labelDe, labelEn: m.labelEn })
    }
  }
  return out
}

/**
 * One bilingual "module(s) not evaluated" sentence for the degraded modules
 * of a single file side, or null when there is nothing to report — mirrors
 * bilingual-message.ts's joinMissingReasons shape ({ de, en }), consumed
 * directly by qaf-provenance.tsx's BilingualText.
 */
export function degradedModulesSentence(modules: readonly DegradedModule[]): { de: string; en: string } | null {
  if (modules.length === 0) return null
  return {
    de: `Modul(e) nicht ausgewertet — Detail-Sheet vorhanden, aber Kopfzeile nicht zuordenbar: ${modules.map((m) => m.labelDe).join(', ')}.`,
    en: `Module(s) not evaluated — detail sheet present but its header could not be mapped: ${modules.map((m) => m.labelEn).join(', ')}.`,
  }
}
