// Der V2-Envelope gegen seine eigenen Zusagen.
//
// Die Bereichsliste ist der Massstab aus dem Golden File. Zwei Eigenschaften
// tragen das Format, und beide sind hier festgehalten:
//
//   1. Die Bereiche sind **fest**. Ein Dokument, dessen Abschnitte je nach Lauf
//      erscheinen und verschwinden, lässt sich zwischen zwei Ständen nicht
//      vergleichen — und genau dafür gibt es das Format.
//   2. Ein nicht berechneter Bereich **sagt das**. Sonst ist nicht unterscheidbar,
//      ob es keine Befunde gab oder ob niemand hingesehen hat.
//
// FIXTURE-DATEN-REGEL: alle Werte unten sind frei erfunden.

import { describe, it, expect } from 'vitest'
import { buildV2Export, missingAreas, V2_AREAS } from '../v2-export'
import type { ValidationResult } from '../export-validation'

const VALIDATION = {
  checks: [],
  passed: true,
} as unknown as ValidationResult

const basis = (areas: Record<string, unknown> = {}, notApplicable?: string[]) =>
  buildV2Export({
    areas: areas as never,
    notApplicable: notApplicable as never,
    validation: VALIDATION,
    generatedAt: '2026-08-02T00:00:00.000Z',
  })

describe('V2-Envelope — feste Bereichsliste', () => {
  it('führt jeden Bereich, auch wenn nichts berechnet wurde', () => {
    const doc = basis()

    for (const area of V2_AREAS) {
      expect(doc.areas).toHaveProperty(area)
      expect(doc.section_state).toHaveProperty(area)
    }
    expect(Object.keys(doc.areas)).toHaveLength(V2_AREAS.length)
  })

  it('hält die Reihenfolge der Bereiche fest', () => {
    // Reihenfolge ist Teil des Vertrags: Zwei Läufe über dieselben Daten
    // müssen byteweise dasselbe Dokument ergeben (Kap. 10, Determinismus).
    expect(Object.keys(basis().areas)).toEqual([...V2_AREAS])
  })
})

describe('V2-Envelope — ein fehlender Bereich sagt, dass er fehlt', () => {
  it('markiert nicht berechnete Bereiche und meldet sie', () => {
    const doc = basis({ all_differences: { count: 2, records: [] } })

    expect(doc.section_state.all_differences.status).toBe('populated')
    expect(doc.section_state.material_analysis.status).toBe('not_computed')
    expect(missingAreas(doc)).toContain('material_analysis')
    expect(missingAreas(doc)).not.toContain('all_differences')
  })

  it('unterscheidet „geprüft, nichts gefunden" von „nicht berechnet"', () => {
    // Der Kern der Ehrlichkeits-Doktrin: Ein leeres Ergebnis ist eine Aussage,
    // ein fehlendes Ergebnis ist keine.
    const doc = basis({ data_quality: { count: 0, findings: [] }, material_analysis: undefined })

    expect(doc.section_state.data_quality.status).toBe('populated')
    expect(doc.section_state.material_analysis.status).toBe('not_computed')
  })

  it('nennt einen leeren berechneten Bereich „empty_no_findings"', () => {
    const doc = basis({ identity_and_premise_changes: {} })

    expect(doc.section_state.identity_and_premise_changes.status).toBe('empty_no_findings')
    expect(missingAreas(doc)).not.toContain('identity_and_premise_changes')
  })

  it('trennt „nicht anwendbar" von „nicht berechnet"', () => {
    // Ein Bereich, der für diesen Vergleichstyp gar nicht gilt, ist kein
    // Versäumnis — das darf die Vollständigkeitsmeldung nicht verwischen.
    const doc = basis({ raw_material_and_risk_analysis: null }, ['raw_material_and_risk_analysis'])

    expect(doc.section_state.raw_material_and_risk_analysis.status).toBe('not_applicable')
    expect(missingAreas(doc)).not.toContain('raw_material_and_risk_analysis')
  })
})

describe('V2-Envelope — Gesamtzustand', () => {
  it('steht auf partial, solange ein Bereich unberechnet ist', () => {
    expect(basis().analysis_status).toBe('partial')
  })

  it('steht auf complete, wenn jeder Bereich berechnet wurde', () => {
    const alle = Object.fromEntries(V2_AREAS.filter((a) => a !== 'validation').map((a) => [a, { ok: true }]))

    expect(basis(alle).analysis_status).toBe('complete')
    expect(missingAreas(basis(alle))).toEqual([])
  })

  it('nimmt den Zeitstempel von aussen, damit der Lauf reproduzierbar bleibt', () => {
    // Ein selbst gesetztes `new Date()` machte zwei Läufe über dieselben Daten
    // unterscheidbar und damit den Determinismus-Nachweis wertlos.
    expect(basis().generated_at).toBe('2026-08-02T00:00:00.000Z')
  })
})
