// V2-Envelope: Vergleichstyp und Sektionszustand (R-23/R-24, Befunde F-20/F-22).

import { describe, it, expect } from 'vitest'
import {
  deriveComparisonType,
  sectionStateOf,
  QAF_CONVENTIONS,
  type ComparisonIdentity,
} from '../export-envelope'

const identity = (over: Partial<ComparisonIdentity> = {}): ComparisonIdentity => ({
  partNumberAward: '1234567',
  partNumberCurrent: '1234567',
  supplierAward: 'Lieferant A',
  supplierCurrent: 'Lieferant A',
  siteAward: 'Werk 1',
  siteCurrent: 'Werk 1',
  ...over,
})

describe('deriveComparisonType (R-23)', () => {
  it('erkennt den zeitlichen Vergleich desselben Projekts', () => {
    const v = deriveComparisonType(identity())
    expect(v.type).toBe('temporal_same_project')
    expect(v.basis).toBe('derived_from_identity')
    expect(v.evidence).toContain('gleicher Standort')
  })

  it('erkennt den Standortvergleich', () => {
    const v = deriveComparisonType(identity({ siteCurrent: 'Werk 2' }))
    expect(v.type).toBe('cross_site_same_part')
    expect(v.basis).toBe('derived_from_identity')
  })

  it('erkennt den Lieferantenvergleich', () => {
    const v = deriveComparisonType(identity({ supplierCurrent: 'Lieferant B', siteCurrent: 'Werk 9' }))
    expect(v.type).toBe('cross_supplier_same_part')
  })

  it('ordnet verschiedene Sachnummern nicht als Projektvergleich ein', () => {
    const v = deriveComparisonType(identity({ partNumberCurrent: '7654321' }))
    expect(v.type).toBe('other_declared')
    expect(v.evidence).toContain('Sachnummern unterscheiden sich')
  })

  it('rät nicht, wenn die Sachnummer fehlt', () => {
    // Genau der Fall aus der Praxis: eine Datei trägt die Nummer, die andere
    // lässt das Feld leer. Eine Einordnung wäre hier erfunden.
    const v = deriveComparisonType(identity({ partNumberCurrent: null }))
    expect(v.type).toBe('other_declared')
    expect(v.basis).toBe('undetermined')
  })

  it('markiert eine Einordnung als unbestimmt, wenn Standort oder Lieferant fehlen', () => {
    const v = deriveComparisonType(identity({ siteAward: null, siteCurrent: null }))
    expect(v.type).toBe('temporal_same_project')
    expect(v.basis).toBe('undetermined') // plausibel, aber nicht belegt
  })

  it('behandelt Leerstrings wie fehlende Werte', () => {
    const v = deriveComparisonType(identity({ supplierCurrent: '   ' }))
    expect(v.basis).toBe('undetermined')
  })

  it('ignoriert Gross-/Kleinschreibung und Rand-Leerzeichen', () => {
    const v = deriveComparisonType(identity({ supplierCurrent: '  lieferant a ' }))
    expect(v.type).toBe('temporal_same_project')
    expect(v.basis).toBe('derived_from_identity')
  })
})

describe('sectionStateOf (R-24)', () => {
  it('unterscheidet befüllt von leer', () => {
    expect(sectionStateOf([{ a: 1 }]).status).toBe('populated')
    expect(sectionStateOf([]).status).toBe('empty_no_findings')
    expect(sectionStateOf(null).status).toBe('empty_no_findings')
    expect(sectionStateOf({}).status).toBe('empty_no_findings')
  })

  it('unterscheidet „nicht anwendbar" von „leer"', () => {
    // Der Kern von F-22: beides sah vorher identisch aus.
    expect(sectionStateOf([], { applicable: false }).status).toBe('not_applicable')
  })

  it('unterscheidet „nicht berechnet" von allem anderen', () => {
    const s = sectionStateOf([{ a: 1 }], { computed: false })
    expect(s.status).toBe('not_computed')
  })

  it('lässt „nicht berechnet" auch dann gelten, wenn Inhalt vorläge', () => {
    // Die Herkunft der Aussage zählt, nicht was zufällig im Objekt steht.
    expect(sectionStateOf([{ a: 1 }], { applicable: false, computed: false }).status).toBe('not_computed')
  })

  it('gibt zu jedem Zustand eine deutsche Begründung', () => {
    for (const s of [
      sectionStateOf([{ a: 1 }]),
      sectionStateOf([]),
      sectionStateOf([], { applicable: false }),
      sectionStateOf([], { computed: false }),
    ]) {
      expect(s.reasonDe.length).toBeGreaterThan(0)
    }
  })
})

describe('QAF_CONVENTIONS (R-17/R-18)', () => {
  it('deklariert Delta-Richtung und Vorzeichen-Bedeutung', () => {
    expect(QAF_CONVENTIONS.deltaDefinition).toBe('current_minus_award')
    expect(QAF_CONVENTIONS.signSemantics).toBe('positive_means_more_expensive')
  })

  it('führt für jede Einheit des Vokabulars eine Rundung', () => {
    const rounded = Object.keys(QAF_CONVENTIONS.rounding)
    for (const unit of ['EUR_per_piece', 'EUR', 'pct_decimal', 'seconds']) {
      expect(rounded).toContain(unit)
    }
  })

  it('hält die Brücken-Toleranz mit der Engine synchron', async () => {
    // Eine Konvention, die etwas anderes behauptet als der Code tut, ist
    // schlimmer als keine.
    const { BRIDGE_MIN_RESIDUAL } = await import('../summary-view')
    expect(QAF_CONVENTIONS.tolerances.bridgeEur).toBe(BRIDGE_MIN_RESIDUAL)
  })
})
