// Werkzeug-Zuordnungen in Differenzsätze überführen (Spezifikation Kap. 7.6).
//
// Die Werkzeuganalyse kennt ihre eigene Sprache — Zweitwerkzeug, neuer Umfang,
// verschobene Zeile. Der Differenzkatalog kennt nur ein geschlossenes
// Vokabular, dafür bereichsübergreifend. Diese Datei ist die Übersetzung
// zwischen beiden, und sie ist bewusst getrennt gehalten: Die Werkzeuganalyse
// soll nichts über den Katalog wissen müssen.

import type { RawDifference, DifferenceCell, DifferenceKind } from './all-differences'
import type { ToolMapping } from './tooling-analysis'

const SHEET = 'SBM-DEVICES-FWZ'
/** Spalte, in der die Werkzeugsumme steht. */
const AMOUNT_COLUMN = 'AP'

const cell = (fileRole: 'award' | 'current', row: number, hasValue: boolean): DifferenceCell => ({
  fileRole,
  sheet: SHEET,
  cell: `${AMOUNT_COLUMN}${row}`,
  formula: null,
  valueState: hasValue ? 'constant' : 'empty',
})

/**
 * Art der Veränderung aus der Klassifikation ableiten.
 *
 * Neuer Umfang und Zweitwerkzeug sind beides Zugänge — der Unterschied steckt
 * in der Beschreibung und in der Brücke, nicht im Vokabular des Katalogs. Eine
 * eigene Art dafür zu erfinden würde den Katalog bereichsspezifisch machen und
 * genau die Auswertbarkeit kosten, für die er da ist.
 */
function kindOf(m: ToolMapping): DifferenceKind {
  if (m.status === 'new') return 'added'
  if (m.status === 'removed') return 'removed'
  if (m.status === 'changed') return 'changed'
  return 'moved'
}

/**
 * Differenzsätze aus den Werkzeug-Zuordnungen.
 *
 * Unveränderte Werkzeuge, die auch nicht verschoben wurden, erzeugen keinen
 * Satz: Ein Katalog, in dem jede Zeile steht, ist keine Differenzliste mehr,
 * sondern eine Kopie des Blatts.
 */
const PER_PIECE_TOLERANCE = 0.00005
/** Spalte, in der die Stückumlage steht. */
const PER_PIECE_COLUMN = 'AQ'

export function differencesFromTooling(
  mappings: readonly ToolMapping[],
  relatedDqByRow: ReadonlyMap<number, string[]> = new Map(),
): RawDifference[] {
  const out: RawDifference[] = []

  for (const m of mappings) {
    const anchorRow = m.currentRow ?? m.awardRow
    const dq = anchorRow === null ? [] : (relatedDqByRow.get(anchorRow) ?? [])
    const umlageGeaendert = m.perPieceDelta !== null && Math.abs(m.perPieceDelta) > PER_PIECE_TOLERANCE

    const einmalzahlungUnveraendert = m.status === 'unchanged' && !m.rowMoved
    // Eine Position ohne jeden Einmalbetrag bekommt keinen Satz in EUR. Sonst
    // stünde eine Vorrichtung zweimal im Katalog: einmal mit einem Betrag, den
    // es nicht gibt, und einmal mit ihrer Stückumlage, um die es tatsächlich geht.
    const ohneEinmalbetrag = (m.oneTimeAward ?? 0) === 0 && (m.oneTimeCurrent ?? 0) === 0
    if (!einmalzahlungUnveraendert && !(ohneEinmalbetrag && umlageGeaendert)) {
      const cells: DifferenceCell[] = []
      if (m.awardRow !== null) cells.push(cell('award', m.awardRow, m.oneTimeAward !== null))
      if (m.currentRow !== null) cells.push(cell('current', m.currentRow, m.oneTimeCurrent !== null))

      out.push({
        area: 'SBM',
        kind: kindOf(m),
        // Das Werkzeugblatt wird ohne Formelvergleich gelesen (formula ist an
        // jeder Fundstelle null), und seine Deltas rechnet die Zuordnung
        // selbst — beide Zusatzangaben sind hier ehrlich leer.
        formulaFindingKind: null,
        descriptionDe: m.evidenceDe,
        valueAward: m.oneTimeAward,
        valueCurrent: m.oneTimeCurrent,
        delta: m.delta,
        deltaNullReason: null,
        unit: 'EUR',
        cells,
        relatedDq: dq,
        anchorRow,
      })
    }

    // Die Stückumlage ist eine eigene Preisdimension. Bliebe sie an der
    // Einmalzahlung hängen, verschwände jede Vorrichtung, deren Umlage sich
    // ändert, während der Einmalbetrag gleich bleibt — im Anlassfall genau die
    // Position, deren Kostenbasis gelöscht wurde.
    if (umlageGeaendert) {
      const cells: DifferenceCell[] = []
      if (m.awardRow !== null) {
        cells.push({
          fileRole: 'award',
          sheet: SHEET,
          cell: `${PER_PIECE_COLUMN}${m.awardRow}`,
          formula: null,
          valueState: m.perPieceAward === null ? 'empty' : 'constant',
        })
      }
      if (m.currentRow !== null) {
        cells.push({
          fileRole: 'current',
          sheet: SHEET,
          cell: `${PER_PIECE_COLUMN}${m.currentRow}`,
          formula: null,
          valueState: m.perPieceCurrent === null ? 'empty' : 'constant',
        })
      }

      out.push({
        area: 'SBM',
        kind: m.perPieceAward === null ? 'added' : m.perPieceCurrent === null ? 'removed' : 'changed',
        formulaFindingKind: null,
        descriptionDe: `Stückumlage für „${m.part}" verändert.`,
        valueAward: m.perPieceAward,
        valueCurrent: m.perPieceCurrent,
        delta: m.perPieceDelta,
        deltaNullReason: null,
        unit: 'EUR_per_piece',
        cells,
        relatedDq: dq,
        anchorRow,
      })
    }
  }

  return out
}
