// Stabile Zeilenmenge der Metriktabelle (V2-Spezifikation R-22, Befund F-19).
//
// Drei reale Läufe lieferten 14, 15 und 13 Zeilen: eine Metrik ohne persistierte
// Diff-Zeile wurde weggelassen statt mit null ausgegeben. Kein Konsument — UI,
// Export, Regressionsvergleich, spätere KI-Schicht — kann sich dann auf die
// Zeilenmenge verlassen; im HICE-Lauf fehlte ausgerechnet die Transportzeile,
// deren Memo-Posten um 54,6 % gestiegen war.
//
// Die Registry-Reihenfolge ist zugleich die Ausgabereihenfolge; Einmalzahlungen
// haben eine eigene Sektion und gehören weiterhin nicht in diese Tabelle.

import { describe, it, expect } from 'vitest'
import { buildMetricsTable, type SummaryDiffRowData } from '../summary-view'
import { SUMMARY_ROW_REGISTRY } from '../summary-row-registry'

function row(metric_key: string, alt: number | null, neu: number | null): SummaryDiffRowData {
  return {
    metric_key,
    alt_value: alt,
    neu_value: neu,
    delta_absolute: alt !== null && neu !== null ? neu - alt : null,
    delta_percent: alt !== null && neu !== null && alt !== 0 ? (neu - alt) / Math.abs(alt) : null,
    currency: 'EUR',
    status: 'anstieg',
    source_alt: alt !== null ? 'P11' : null,
    source_neu: neu !== null ? 'P11' : null,
  }
}

/** Die Zeilen, die in dieser Tabelle erwartet werden: alles außer Einmalzahlungen. */
const EXPECTED_KEYS = SUMMARY_ROW_REGISTRY.filter(
  (s) => s.role !== 'one_time' && s.role !== 'one_time_total',
).map((s) => s.metricKey)

describe('buildMetricsTable — stabile Zeilenmenge (R-22)', () => {
  it('gibt bei vollständiger Eingabe die komplette Registry-Zeilenmenge aus', () => {
    const table = buildMetricsTable(EXPECTED_KEYS.map((k) => row(k, 1, 2)))
    expect(table.map((r) => r.metricKey)).toEqual(EXPECTED_KEYS)
  })

  it('liefert dieselbe Zeilenmenge, auch wenn fast nichts persistiert ist', () => {
    const sparse = buildMetricsTable([row('materialCosts', 1, 2)])
    expect(sparse.map((r) => r.metricKey)).toEqual(EXPECTED_KEYS)
  })

  it('liefert die Zeilenmenge selbst bei leerer Eingabe', () => {
    expect(buildMetricsTable([]).map((r) => r.metricKey)).toEqual(EXPECTED_KEYS)
  })

  it('gibt eine fehlende Metrik als null aus statt sie wegzulassen', () => {
    const table = buildMetricsTable([row('materialCosts', 1, 2)])
    const transport = table.find((r) => r.metricKey === 'transportSupplierToBMW')

    expect(transport).toBeDefined()
    expect(transport!.alt).toBeNull()
    expect(transport!.neu).toBeNull()
    expect(transport!.deltaAbsolute).toBeNull()
    expect(transport!.deltaPercent).toBeNull()
    expect(transport!.status).toBeNull()
    expect(transport!.sourceAlt).toBeNull()
    expect(transport!.sourceNeu).toBeNull()
  })

  it('reicht vorhandene Werte unverändert durch', () => {
    const table = buildMetricsTable([row('materialCosts', 1.5, 2.25)])
    const material = table.find((r) => r.metricKey === 'materialCosts')

    expect(material!.alt).toBe(1.5)
    expect(material!.neu).toBe(2.25)
    expect(material!.deltaAbsolute).toBeCloseTo(0.75, 6)
    expect(material!.status).toBe('anstieg')
    expect(material!.sourceAlt).toBe('P11')
  })

  it('hält die Einmalzahlungen weiterhin aus dieser Tabelle heraus', () => {
    const keys = buildMetricsTable([row('oneTimeTools', 1, 2)]).map((r) => r.metricKey)
    expect(keys).not.toContain('oneTimeTools')
    expect(keys).not.toContain('oneTimeDevelopment')
    expect(keys).not.toContain('totalOneTimePayment')
  })

  it('ignoriert Zeilen, die keiner Registry-Metrik entsprechen', () => {
    // Ein unbekannter metric_key aus einer älteren Engine-Version darf die
    // Zeilenmenge nicht aufblähen — Struktur ist konstant, nur Inhalte variieren.
    const table = buildMetricsTable([row('materialCosts', 1, 2), row('legacyPhantomMetric', 9, 9)])
    expect(table.map((r) => r.metricKey)).toEqual(EXPECTED_KEYS)
  })
})
