// Datenqualität gegen die anonymisierte Ableitung des Referenzfalls.
//
// Der Golden-Case daneben braucht die echten Kalkulationen und übergeht sich
// überall ausser beim Betreiber. Diese Fixture trägt dieselbe Blattstruktur —
// Infozeilen, Baugruppengrenzen als Lücken in der Zeilenfolge, denselben
// Widerspruch zwischen einer Infozeile und ihren Komponenten — nur mit
// pseudonymisierten Namen und skalierten Beträgen.

import { describe, it, expect } from 'vitest'
import { readFileSync } from 'node:fs'
import path from 'node:path'
import { groupByTotalLine, detectStaleTotalLines, type NamedCostRow } from '../data-quality'

interface ToolingFixture {
  toolsCurrent: Array<{ row: number; part: string; oneTimeCost: number | null; isTotalLine: boolean }>
  expected: { totalLineGroups: number; staleTotalLines: number }
}

const FIXTURE: ToolingFixture = JSON.parse(
  readFileSync(path.join(__dirname, 'fixtures/tooling-anonymised.json'), 'utf8'),
)

const rows = (): Array<NamedCostRow & { isTotalLine?: boolean }> =>
  FIXTURE.toolsCurrent.map((t) => ({ row: t.row, name: t.part, cost: t.oneTimeCost, isTotalLine: t.isTotalLine }))

describe('D07 — Infozeilen der anonymisierten Ableitung', () => {
  it('erkennt alle Infozeilen des Blatts', () => {
    expect(groupByTotalLine(rows())).toHaveLength(FIXTURE.expected.totalLineGroups)
  })

  it('meldet genau den einen widersprüchlichen Zwischenwert', () => {
    // Zu viel zu melden ist so schädlich wie zu wenig: ein Bericht mit einem
    // falschen Grossbefund wird zu Recht nicht mehr gelesen.
    expect(detectStaleTotalLines(groupByTotalLine(rows()), 'current')).toHaveLength(
      FIXTURE.expected.staleTotalLines,
    )
  })

  it('schliesst die übrigen Baugruppen auf den Cent', () => {
    // Der Beleg dafür, dass die Gruppengrenze richtig gezogen ist.
    const groups = groupByTotalLine(rows())
    const geschlossen = groups.filter(
      (g) => g.componentSum !== null && g.totalValue !== null && Math.abs(g.totalValue - g.componentSum) <= 0.005,
    )
    expect(geschlossen).toHaveLength(groups.length - FIXTURE.expected.staleTotalLines)
  })

  it('zieht die Gruppengrenze an der Lücke in der Zeilenfolge', () => {
    // Ohne diese Grenze zöge die letzte Gruppe den angehängten Block an sich.
    const groups = groupByTotalLine(rows())
    const letzte = groups[groups.length - 1]
    const hoechsteZeile = Math.max(...FIXTURE.toolsCurrent.map((t) => t.row))
    expect(letzte.componentRows[letzte.componentRows.length - 1]).toBeLessThan(hoechsteZeile)
  })
})
