// Welche Zahl in einem QAF-Workbook ist ein Geldbetrag — und darf deshalb für
// eine anonymisierte Fixture mit einem Faktor skaliert werden?
//
// Diese Frage hat drei naheliegende falsche Antworten:
//
//   1. „Zellen mit Währungsformat."  Die realen 8.8-Arbeitsmappen tragen in
//      1513 Zahlzellen KEIN einziges Währungs-Zahlenformat (gemessen, 12
//      Blätter, 8946 belegte Zellen). Diese Regel trifft null Zellen und lässt
//      sämtliche echten Beträge im Klartext stehen — bei grünem Testlauf.
//   2. „Felder mit dataType currency."  `currency` ist in der Registry
//      MEHRDEUTIG und taugt allein nicht als Diskriminator: von 48 Feldern
//      sind 10 Währungs-BEZEICHNER ("Beschaffungswährung BW" → EUR/USD,
//      in MANUFACTURING/MATERIAL/SBM/LOGISTICS/LAF) und 38 echte BETRÄGE
//      ("Materialkosten", "SUMME HERSTELLKOSTEN", in SUMMARY/LC_CN/WAF/LEK).
//      Kein Metadatum trennt die beiden Gruppen — nur die Bedeutung des
//      Labels, und 47 der 48 tragen gar keine `unit`.
//   3. „Alle Zahlen."  Dann skalieren auch Mengen und Zeiten mit, und
//      Preis × Menge = Summe bricht (s · s = s²).
//
// Der tragfähige Diskriminator ist die `unit` der kanonischen Feldregistry
// (canonical-fields.ts). Sie ist bereits da, ist gepflegt, und sie unterscheidet
// genau das, worauf es ankommt.
//
// ── Warum die Verhältnis-Regel nötig ist ────────────────────────────────────
//
// Mit Skalierungsfaktor s bleibt die Arbeitsmappe nur dann in sich stimmig,
// wenn jede Formel weiterhin aufgeht:
//
//   FEK [BW]        = Lohnkosten [BW/h] × Zeit [s]      →  s · 1 = s   ✓
//   FK [AW]         = FK [BW] × Wechselkurs [AW/BW]     →  s · 1 = s   ✓
//   Ausschusskosten = FK [AW] × Ausschussrate [%]       →  s · 1 = s   ✓
//
// Der Wechselkurs ist Geld je Geld und damit skalierungsinvariant. Würde man
// ihn mitskalieren, käme s² heraus und die Fixture widerspräche sich selbst.
// Genau deshalb reicht „Einheit enthält BW oder AW" als Regel nicht aus.

/**
 * Währungs-Platzhalter der QAF-Vorlagen: BW = Beschaffungs-, AW = Angebotswährung.
 * `Betrag` steht in `lek_hourly_rate` ("Betrag/h") für dieselbe Sache.
 */
const MONEY_TOKENS = new Set(['BW', 'AW', 'Betrag'])

/**
 * `scale`   — sicher ein Geldbetrag, skalieren.
 * `keep`    — sicher kein Geldbetrag, unverändert lassen.
 * `unclear` — nicht entscheidbar. Der Aufrufer MUSS diesen Fall behandeln,
 *             statt ihn wie `keep` zu verbuchen: eine unerkannte Geldzelle
 *             bliebe sonst als echter Wert in der Fixture stehen.
 */
export type ScaleVerdict = 'scale' | 'keep' | 'unclear'

export type ScaleDecision = {
  verdict: ScaleVerdict
  /** Nur true bei `scale` — bequemer Zugriff, ohne den unklaren Fall zu verschlucken. */
  scale: boolean
  /** Kurzbegründung — wandert in das Fixture-Manifest, damit die Entscheidung nachlesbar ist. */
  reason: string
}

const decide = (verdict: ScaleVerdict, reason: string): ScaleDecision => ({
  verdict,
  scale: verdict === 'scale',
  reason,
})

/**
 * Entscheidet anhand der Einheit eines kanonischen Feldes, ob sein Wert ein
 * skalierbarer Geldbetrag ist.
 *
 * Erwartet die `unit` genau so, wie die Registry sie führt ("BW", "AW/BW",
 * "BW/h", "%", "s", "Stück"), plus optional den `dataType` des Feldes.
 *
 * Ohne `unit` lässt sich ein Feld mit `dataType: "currency"` NICHT entscheiden
 * (siehe Kopfkommentar: 10 Bezeichner gegen 38 Beträge, kein trennendes
 * Metadatum). Dieser Fall liefert `unclear` statt eines stillen `keep`.
 */
export function decideScaling(unit: string | undefined, dataType?: string): ScaleDecision {
  if (unit === undefined || unit.trim() === '') {
    if (dataType === 'currency') {
      return decide(
        'unclear',
        'dataType "currency" ohne Einheit — Betrag oder Währungsbezeichner nicht unterscheidbar',
      )
    }
    return decide('keep', 'keine Einheit — nicht quantifiziertes Feld')
  }

  const parts = unit.split('/').map((p) => p.trim())
  if (parts.length > 2) {
    // Mehrgliedrig: nicht deutbar. `unclear`, nicht `keep` — enthielte sie einen
    // Geldanteil, bliebe der Betrag sonst unbemerkt im Klartext stehen.
    return decide('unclear', `Einheit "${unit}" ist mehrgliedrig und nicht deutbar`)
  }

  const [numerator, denominator] = parts
  const numeratorIsMoney = MONEY_TOKENS.has(numerator)
  const denominatorIsMoney = denominator !== undefined && MONEY_TOKENS.has(denominator)

  if (!numeratorIsMoney) {
    return decide('keep', `Zähler "${numerator}" ist kein Geldwert`)
  }
  if (denominatorIsMoney) {
    // AW/BW, BW/AW: Verhältnis zweier Geldgrößen, kürzt den Faktor weg.
    return decide('keep', `"${unit}" ist Geld je Geld und damit skalierungsinvariant`)
  }

  return decide(
    'scale',
    denominator === undefined ? `"${unit}" ist ein Geldbetrag` : `"${unit}" ist Geld je ${denominator}`,
  )
}

/**
 * Skaliert einen Betrag und rundet auf sechs Nachkommastellen — dieselbe
 * Genauigkeit, die der operator-lokale Referenz-Anonymizer verwendet, damit
 * Verhältnisse und Summen exakt erhalten bleiben.
 */
export function scaleAmount(value: number, factor: number): number {
  return Number((value * factor).toFixed(6))
}
