// Centralized DE/EN worksheet-NAME synonym registry (KAR-905 / P3.1).
//
// Problem this closes (backlog 05-backlog-phasenplan.md [P3.1] + Master-Prompt
// §9): every QAF module parser (material-parser.ts, sbm-parser.ts,
// logistics-parser.ts, rmr-parser.ts, lccn-parser.ts, co2e-parser.ts) grew its
// own `isXxxSheetName(name)` function with the module's known worksheet-tab
// name(s) inlined as a literal string/substring check. That worked (each one
// individually correct — see below), but there was no SINGLE place to look up
// "what worksheet names does Kadi-v2 recognize for module X, and why" — every
// new module name variant (a typo, a locale spelling) meant hunting down and
// editing N different files. This module is that single place; every
// isXxxSheetName below is a thin wrapper around matchesModuleSheetName().
//
// ── Why most of these lists are locale-INVARIANT (the actual P3.1 finding) ──
// The backlog item's own hypothesis was "each module needs a DE alias list and
// an EN alias list, like Fertigungskosten/Manufacturing costs already has."
// Checked against the Leitfaden extraction (02-leitfaden-teil1/2/3.md) for
// every module's own worksheet-name citations: MOST BMW QAF tab names are // allow-customer-string
// fixed, English-language proper nouns/abbreviations that the Leitfaden cites
// VERBATIM even in its own German running text ("Blatt MATERIAL", "Blatt
// SBM-DEVICES-FWZ", "Blatt 'LOGISTICS&CUSTOM'", "Blatt 'RAW MATERIAL RISKS'",
// "Registerblatt 'LC-CN'") — the tab itself is not translated when a supplier
// fills out the DE vs. EN content variant (Abbildung 27 "Sprachauswahl DE/EN"
// only switches the row/column LABEL text inside a sheet, not the sheet's own
// tab name). Only ONE module tab genuinely has two different literal tab
// names depending on file language: MANUFACTURING ("Fertigungskosten" DE vs.
// "Manufacturing costs"/"Manufactering costs" EN — already correctly handled
// pre-existing in qaf-parser.ts, ported here verbatim). The pre-existing
// per-module isXxxSheetName functions were therefore not actually buggy for
// EN files on the sheet-NAME axis — this PR keeps their (correct) matching
// behavior unchanged while centralizing the string source and making the
// DE/EN-invariance finding explicit and evidence-cited, instead of leaving it
// as an unstated assumption baked separately into six files.
//
// KAR-915 update (10.07.2026): this finding was INCOMPLETE for RMR — the
// real V8.8 DE NCAR-Korpus file's tab is literally "Rohstoffrisiken" (a
// genuine DE tab-name translation this P3.1 extraction pass missed, most
// likely because the Leitfaden text this pass was sourced from only ever
// quotes the sheet in its EN form). RMR's own list below now carries a
// DE-only 'rohstoffrisiken' alias alongside the locale-invariant
// 'raw material risk' one — see that list's own comment for the parse-
// correctness impact this had before the fix (findRmrWorksheet() returning
// null on every "Rohstoffrisiken"-tabbed file, not just V8.8 ones).
//
// tdd-guard:skip — pure constant data + a thin lookup function, same category
// as canonical-fields.ts (data) — covered by __tests__/module-sheet-names.test.ts.

export type QafSheetModule = 'SUMMARY' | 'MANUFACTURING' | 'MATERIAL' | 'SBM' | 'LOGISTICS' | 'RMR' | 'LC_CN' | 'CO2E'

export interface ModuleSheetNameAlias {
  /** Substring matched case-insensitively against the worksheet's tab name. */
  name: string
  /**
   * Set only when this specific alias string is itself a DE/EN language
   * signal (i.e. a supplier would only ever see this exact tab name if the
   * file's language variant were that language) — undefined when the tab
   * name is locale-invariant (used identically regardless of the file's
   * DE/EN content language). Consumed by language-detection.ts; NOT used by
   * matchesModuleSheetName/isXxxSheetName below (sheet-name RECOGNITION is
   * deliberately insensitive to language — a DE-content file's MATERIAL
   * sheet must be found exactly the same way an EN-content file's is).
   */
  language?: 'de' | 'en'
}

/**
 * DE+EN worksheet-name synonyms per QAF module, evidence-cited. Every entry's
 * evidence is a literal quoted worksheet-name citation in the Leitfaden
 * extraction (02-leitfaden-teil1/2/3.md) or, for the MANUFACTURING typo
 * variant, the pre-existing code comment it was ported from.
 */
export const MODULE_SHEET_NAME_ALIASES: Record<QafSheetModule, readonly ModuleSheetNameAlias[]> = {
  // teil1.md:137/172/223/281/282 "Blatt 'SUMMARY'" (quoted, repeated) is the
  // V9 tab name, used for BOTH DE- and EN-content files (Abbildung 27's
  // language selector switches field labels, not the tab name) — locale-
  // invariant. "Zusammenfassung" is summary-metrics.ts's pre-existing
  // QAF_LEGACY_DE_SUMMARY signal (pickTemplate()) for the older, DE-only
  // legacy template generation that predates the V9 SUMMARY tab naming — a
  // genuine DE-only signal, not a EN/DE pair (there is no "Zusammenfassung"
  // EN counterpart; V9's EN variant is also named "SUMMARY").
  SUMMARY: [{ name: 'summary' }, { name: 'zusammenfassung', language: 'de' }],
  // qaf-parser.ts HEADER_TO_KEY module header (pre-existing, ported
  // verbatim) + teil1.md:544/570/597/619/620/625 "Blatt 'MANUFACTURING
  // COSTS'" (EN) / teil1.md:620 "Blatt '2. FERTIGUNGSKOSTEN' (MANUFACTURING
  // COSTS)" (DE tab literally named "FERTIGUNGSKOSTEN", parenthetical EN
  // gloss) — the ONE module whose tab name genuinely differs DE vs. EN.
  // "manufactering" is BMW's own documented real-file typo (qaf-parser.ts // allow-customer-string
  // sheet-picker comment, already shipped pre-P3.1) — kept as an EN alias,
  // not "corrected" away.
  MANUFACTURING: [
    { name: 'fertigungskosten', language: 'de' },
    { name: 'manufacturing cost', language: 'en' },
    { name: 'manufactering cost', language: 'en' },
  ],
  // teil1.md:290/291/308/332/356/384/410/423/482/500/515/530 "Blatt
  // MATERIAL" (unquoted but consistently capitalized proper-noun usage,
  // repeated 12+ times, never once glossed with a different DE word) —
  // locale-invariant, same word in both languages.
  MATERIAL: [{ name: 'material' }],
  // teil1.md:629/633/662, teil2.md:13/37/53 "Blatt 'SBM-DEVICES-FWZ'"
  // (quoted) — a fixed BMW-internal abbreviation (Sonderbetriebsmittel/ // allow-customer-string
  // Devices/Folgewerkzeuge), never a translated tab name.
  SBM: [{ name: 'sbm-devices-fwz' }, { name: 'sbm' }],
  // teil1.md:223/232 "Blatt 'LOGISTICS&CUSTOM'" (quoted) — English-language
  // proper name used verbatim in the DE-content Leitfaden text too, locale-
  // invariant. Space-around-ampersand variant included defensively (Excel
  // tab-name whitespace is not guaranteed identical to the Leitfaden's own
  // typesetting).
  LOGISTICS: [{ name: 'logistics&custom' }, { name: 'logistics & custom' }, { name: 'logistics' }],
  // teil2.md:144/148/168/169/172/183 "Blatt 'RAW MATERIAL RISKS'" (quoted,
  // plural — the definitive, repeated, quoted citation) vs. teil1.md:332/
  // 426/449 "Registerblatt RAW MATERIAL RISK" (singular, unquoted, same
  // extraction pass's paraphrase of the identical tab). Both forms listed;
  // the singular is a substring of the plural so a single 'raw material
  // risk' check already matches either spelling (pre-existing rmr-parser.ts
  // behavior, unchanged here — just centralized).
  //
  // KAR-915 fix: "Rohstoffrisiken" is the REAL V8.8 DE tab name — verified
  // on the real V8.8 DE NCAR-Korpus file (server-only) — and was MISSING
  // from this list entirely before this PR. Unlike every other module
  // (module header's "why most of these lists are locale-INVARIANT"
  // finding), RMR's tab name genuinely IS translated between DE and EN in
  // the V8.8 template generation: without this alias, findRmrWorksheet()
  // never located the RMR sheet on ANY DE-language file whose tab is
  // "Rohstoffrisiken" rather than the English "RAW MATERIAL RISK(S)" name —
  // parseRmrSheet() silently returned null (file has none) instead of
  // parsing it, on every such file, V8.8 or otherwise (not verified against
  // real V9 DE files as part of this PR — flagged for follow-up). This is a
  // DE-only language signal, not a locale-invariant alias.
  RMR: [{ name: 'raw material risk' }, { name: 'rohstoffrisiken', language: 'de' }],
  // teil2.md:202/203/204/213/254/255 "Registerblatt 'LC-CN'" / "Blatt LC-CN"
  // (quoted + unquoted, both forms) — locale-invariant abbreviation, never
  // translated (Abbildung 30's own title is bilingual-English: "LOCAL
  // CONTENT QUOTATION ANALYSIS FORM ZUSAMMENFASSUNG").
  LC_CN: [{ name: 'lc-cn' }, { name: 'lc cn' }, { name: 'local content' }],
  // teil2.md:278/280/281/283/287/288/307/309/312/362/363 "CO2e" is used
  // throughout as the fixed module name (never translated — "Der Begriff
  // 'CO2e' wird in diesem Leitfaden als Darstellung des Product Carbon
  // Footprint (PCF) verwendet", teil2.md:283); co2e-parser.ts's own module
  // header documents that NO real CO2e-Type file has been seen yet, so
  // whether a real workbook carries a dedicated "CO2e"-named tab at all is
  // itself unconfirmed (documented limitation, ported unchanged) — this
  // list only centralizes the same tolerant name variants co2e-parser.ts
  // already searched for.
  CO2E: [{ name: 'co2e' }, { name: 'carbon footprint' }],
}

/**
 * True when `name` (a worksheet tab name) matches one of `module`'s known
 * DE/EN/typo aliases — case-insensitive substring match, same semantics every
 * pre-existing isXxxSheetName function already used individually. Does NOT
 * apply module-specific exclusions (e.g. MATERIAL vs. RMR both containing the
 * substring "material") — callers that need that keep their own guard, same
 * as before centralization (see material-parser.ts's isMaterialSheetName).
 */
export function matchesModuleSheetName(name: string, module: QafSheetModule): boolean {
  const n = name.toLowerCase()
  return MODULE_SHEET_NAME_ALIASES[module].some((alias) => n.includes(alias.name.toLowerCase()))
}

/**
 * The DE/EN language signal carried by a worksheet tab name, if any — the
 * alias entry that matched `name` for `module`, provided it declared a
 * `language` (locale-invariant aliases return null). First match wins if a
 * name were to match more than one aliases entry (not possible for the
 * current lists — every module's aliases are mutually exclusive substrings).
 * Consumed by language-detection.ts.
 */
export function moduleSheetNameLanguageSignal(name: string, module: QafSheetModule): 'de' | 'en' | null {
  const n = name.toLowerCase()
  const hit = MODULE_SHEET_NAME_ALIASES[module].find((alias) => n.includes(alias.name.toLowerCase()))
  return hit?.language ?? null
}
