// Integration tests: the degraded-parse path of lib/qaf-parser.ts
// (KAR-893/P1.2 — label-anchor + confidence instead of exact-match-only)
// feeding real downstream consumers (rule-engine.ts R2, reconciliation.ts
// fk_detail_sum), not just synthetic QAFRow object literals. Proves the
// task's explicit downstream requirement: "rule-engine (MANDATORY-Felder
// null → R2 greift korrekt statt Crash), reconciliation (fkAW fehlt →
// nicht_pruefbar statt falscher Summe)". Neither rule-engine.ts nor
// reconciliation.ts needed ANY code change for this — both already tolerate
// a genuinely-null mandatory field (see their respective existing unit
// tests); this file exercises that tolerance against the ACTUAL output of a
// degraded parseQAFTemplate() run, not a hand-built stand-in.
//
// Fixtures are entirely synthetic (invented field values) — no real
// Brose/Kiekert/Autoliv data or files.

import { describe, it, expect } from 'vitest'
import ExcelJS from 'exceljs'
import { TEMPLATE_HEADERS, parseQAFTemplate, type QAFRow } from '@/lib/qaf-parser'
import { metricsParse } from './summary-fixtures'
import { evaluateReconciliation, checkReconciliation, type ReconciliationInput } from '../reconciliation'
import { evaluateRuleEngine, type RuleEngineInput } from '../rule-engine'
import type { QafSummary, QafSummaryKey } from '../types'

function summary(values: Partial<Record<QafSummaryKey, string | null>>): QafSummary {
  const keys: QafSummaryKey[] = [
    'partNumber',
    'quotationDate',
    'supplier',
    'partName',
    'variant',
    'project',
    'requestVersion',
    'changeIndex',
    'supplierNo',
    // KAR-910
    'peakVolumeYear',
    'productionStartSop',
    'deliverySite',
    'shiftsPerWeek',
    // QVS-P4
    'plannedCapacity',
    'lotSize',
  ]
  const out = {} as QafSummary
  for (const k of keys) out[k] = { value: values[k] ?? null, cell: null }
  return out
}

const DATA_ROW = ['1', 'Blende', 'Montage', 'Anlage A', 'Werk', 'EUR', 12, 1, 1, 30, 10, 50, 0, 0, 0, 100, 'EUR', 1, 1, 100, 2, 1]

/** A Fertigungskosten workbook whose header row is MISSING "Fertigungskosten
 * FK [AW]" (fkAW) — the 3 core columns (Position/Prozess/FK[BW]) stay intact,
 * so the parse degrades instead of throwing. `fkAW` and its downstream
 * dollar value end up null for every row. */
async function degradedWorkbookFile(): Promise<File> {
  const wb = new ExcelJS.Workbook()
  const ws = wb.addWorksheet('Fertigungskosten')
  const headers = TEMPLATE_HEADERS.filter((h) => h !== 'Fertigungskosten FK [AW]')
  ws.getRow(1).values = [null, ...headers]
  const dataWithoutFkAw = [...DATA_ROW]
  dataWithoutFkAw.splice(TEMPLATE_HEADERS.indexOf('Fertigungskosten FK [AW]'), 1)
  ws.getRow(2).values = [null, ...dataWithoutFkAw]
  const buf = await wb.xlsx.writeBuffer()
  return new File([buf], 'qaf-degraded.xlsx', {
    type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  })
}

describe('parseQAFTemplate degradation -> downstream consumers (KAR-893/P1.2)', () => {
  it('a header missing the fkAW column still parses (degraded), fkAW stays null', async () => {
    const rows = await parseQAFTemplate(await degradedWorkbookFile())
    expect(rows).toHaveLength(1)
    expect(rows[0].fkAW).toBeNull()
    expect(rows[0].prozessbezeichnung).toBe('Montage')
    expect(rows[0].fk).toBe(100)
    expect(rows.mappedFieldCount).toBe(21) // 22 - fkAW
    expect(rows.unmappedHeaders).toEqual([])
    expect(rows.parseConfidence).toBe(1) // the 21 remaining columns are all exact matches
  })

  it('rule-engine R2: the degraded fkAW column produces a real mandatory-field violation, not a crash', async () => {
    const steps = await parseQAFTemplate(await degradedWorkbookFile())
    const input: RuleEngineInput = {
      alt: { summary: summary({ partNumber: '123' }), steps },
      neu: { summary: summary({ partNumber: '123' }), steps },
    }
    // Must not throw — this is the "statt Crash" half of the requirement.
    const violations = evaluateRuleEngine(input)
    const r2 = violations.filter((v) => v.ruleId === 'R2' && v.fieldKey === 'fkAW')
    // One per side (ALT + NEU), both flagging the same missing mandatory field.
    expect(r2).toHaveLength(2)
    expect(r2[0].severity).toBe('kritisch')
    expect(r2[0].messageDe).toContain('Fertigungskosten FK [AW]')
  })

  it('reconciliation fk_detail_sum: the degraded fkAW column yields nicht_pruefbar, never a false Summe', async () => {
    const steps: QAFRow[] = await parseQAFTemplate(await degradedWorkbookFile())
    const input: ReconciliationInput = {
      side: 'NEU',
      steps,
      summaryMetrics: metricsParse({ manufacturingCosts: 100 }),
    }
    const results = evaluateReconciliation(input)
    const r = results.find((x) => x.checkId === 'fk_detail_sum')
    expect(r?.status).toBe('nicht_pruefbar')
    expect(r?.expected).toBeNull()
    expect(r?.actual).toBeNull()

    const issue = checkReconciliation(input).find((i) => i.type === 'recon_fk_detail_sum_nicht_pruefbar')
    expect(issue).toBeDefined()
    expect(issue?.severity).toBe('hinweis')
  })
})
