// Unit tests for material-matrix-parser.ts (KAR-931 / Multi-QAF-Programm
// P1.3).
//
// FIXTURE-DATEN-REGEL (same discipline as synthetic-fixtures.ts's own header
// comment, KAR-929 adversarial review F4 — merge-blocker class): every code,
// number, formula text, and cell reference below is FREE INVENTION. Before
// adding any new literal here: grep -inE "<code-or-number>"
// /root/aria/brain/01-Projekte/supplierpulse-multi-qaf/10-analyse-*.md must
// be EMPTY. Component/part labels deliberately invented ("Bracket A",
// "Sensor B", "Screw C", "Gasket D") — not real customer part designations. // allow-customer-string
//
// These grids reproduce the STRUCTURAL patterns documented in the 4 real
// analyzed workbooks (10-analyse-clarwe-eu.md D / -mx.md F / -nafta.md D /
// -ncar.md E — shared material master + per-variant quantity-factor columns,
// factor diversity 0/1/2/12/28/71, blank-vs-explicit-zero distinction,
// #DIV/0!-carrying padding rows, a SUMPRODUCT/SUM total row below the data)
// with entirely invented content.
//
// KAR-931 adversarial-review fix F1: the total row (row 12 below) now
// carries a Label ("Summe Materialkosten") with NO position number —
// reproducing the documented real pattern (10-analyse-clarwe-eu.md D: row
// 159 "Summe Materialkosten") that the padding filter's old "no position
// AND no label" gate did NOT catch. The PRIOR version of this fixture left
// both position AND label blank on the total row, which never exercised the
// bug at all.

import { describe, it, expect, beforeAll } from 'vitest'
import { gridFromCells } from '../../summary-parser'
import { columnIndexToLetter, type VariantDefinition, type VariantDimensions } from '../types'
import {
  parseMaterialMatrix,
  locateMaterialMatrixHeader,
  type MaterialMatrixGridInput,
  type MaterialMatrixParseResult,
} from '../material-matrix-parser'

// ── Grid-building helpers (mirrors header-parser.test.ts's own pattern) ────

function formulaGridFromCells(cells: Record<string, string>): (string | null)[][] {
  let maxRow = 0
  let maxCol = 0
  const parsed: Array<{ row: number; col: number; value: string }> = []
  for (const [addr, value] of Object.entries(cells)) {
    const m = /^([A-Za-z]+)(\d+)$/.exec(addr)
    if (!m) throw new Error(`bad A1 address: ${addr}`)
    let col0 = 0
    for (const ch of m[1].toUpperCase()) col0 = col0 * 26 + (ch.charCodeAt(0) - 64)
    col0 -= 1
    const row0 = Number(m[2]) - 1
    parsed.push({ row: row0, col: col0, value })
    if (row0 > maxRow) maxRow = row0
    if (col0 > maxCol) maxCol = col0
  }
  const grid: (string | null)[][] = Array.from({ length: maxRow + 1 }, () => new Array(maxCol + 1).fill(null))
  for (const { row, col: c, value } of parsed) grid[row][c] = value
  return grid
}

function makeVariant(id: string, columnIndex1: number): VariantDefinition {
  const dimensions: VariantDimensions = {}
  return {
    stableInternalId: id,
    originalColumn: columnIndexToLetter(columnIndex1),
    originalColumnIndex: columnIndex1,
    originalVariantNumber: null,
    originalLabels: [id],
    normalizedLabels: [id.toLowerCase()],
    compositeCanonicalKey: id,
    dimensions,
    annualVolume: null,
    peakVolume: null,
    lifetimeVolume: null,
    currency: null,
    activeState: 'active',
    sourceReferences: [],
    confidence: 0.85,
  }
}

const HEADER_CELLS = {
  B5: 'Positionsnummer',
  D5: 'Teilebenennung',
  F5: 'Beschaffungswährung',
  G5: 'Materialkosten pro Mengeneinheit (BW)',
  H5: 'Wechselkurs',
  I5: 'Materialkosten pro Mengeneinheit (AW)',
  L5: 'Mengenfaktor-Durchschnitt',
  M5: 'Stückzahl pro Bauteil',
}

// v1=N(14), v2=O(15), v3=P(16), v4=R(18, deliberately no total formula)
const V1 = makeVariant('variant-alpha', 14)
const V2 = makeVariant('variant-beta', 15)
const V3 = makeVariant('variant-gamma', 16)
const V4 = makeVariant('variant-delta', 18)

function buildPrimaryGrid(): MaterialMatrixGridInput {
  const cells: Record<string, unknown> = {
    ...HEADER_CELLS,
    // Row 6: pos 1, Bracket A — baseline factor 1 for all 3 variants.
    B6: '1',
    D6: 'Bracket A',
    F6: 'EUR',
    G6: 10,
    H6: 1,
    I6: 10,
    N6: 1,
    O6: 1,
    P6: 1,
    R6: 1,
    // Row 7: pos 2, Sensor B — v2 BLANK (not applicable), v3=12.
    B7: '2',
    D7: 'Sensor B',
    F7: 'EUR',
    G7: 5,
    H7: 1,
    I7: 5,
    N7: 2,
    P7: 12,
    R7: 1,
    // Row 8: pos 3, Screw C — v1 explicit literal 0 (distinct from blank), v3 BLANK.
    B8: '3',
    D8: 'Screw C',
    F8: 'EUR',
    G8: 1,
    H8: 1,
    I8: 1,
    N8: 0,
    O8: 71,
    // Row 9: padding — no position, no label, #DIV/0! cached in control cols.
    L9: '#DIV/0!',
    M9: '#DIV/0!',
    // Row 10: pos 1, Bracket A AGAIN — split/collision row (same identity as row 6).
    B10: '1',
    D10: 'Bracket A',
    F10: 'EUR',
    G10: 10,
    H10: 1,
    I10: 10,
    N10: 1,
    O10: 1,
    P10: 1,
    // Row 11: pos 4, Gasket D — v1=28 (real factor diversity value), v2 explicit 0, v3 BLANK.
    B11: '4',
    D11: 'Gasket D',
    F11: 'EUR',
    G11: 2,
    H11: 1,
    I11: 2,
    N11: 28,
    O11: 0,
    // Row 12: total row — real-pattern (Label set, Position BLANK,
    // 10-analyse-clarwe-eu.md D "Summe Materialkosten") with SUMPRODUCT-shaped
    // formulas for v1/v2/v3 (v4 deliberately has none).
    D12: 'Summe Materialkosten',
    N12: 86, // bestanden: 1*10 + 2*5 + 0*1 + 1*10 + 28*2 = 86
    O12: 91, // bestanden: 1*10 + 71*1 + 1*10 + 0*2 = 91
    P12: 100, // abweichung: recomputed expected is 80 (1*10 + 12*5 + 1*10)
  }
  const grid = gridFromCells(cells)
  const formulaGrid = formulaGridFromCells({
    N12: '=SUMPRODUCT($I$6:$I$11,N6:N11)',
    O12: '=SUMPRODUCT($I$6:$I$11,O6:O11)',
    P12: '=SUMPRODUCT($I$6:$I$11,P6:P11)',
  })
  return { sheet: 'Material', grid, formulaGrid }
}

// ── locateMaterialMatrixHeader ──────────────────────────────────────────

describe('locateMaterialMatrixHeader', () => {
  it('locates the header row via DE label synonyms', () => {
    const input = buildPrimaryGrid()
    const result = locateMaterialMatrixHeader(input, 0, 40, 1, 30)
    expect(result?.row).toBe(5)
    expect(result?.columns.positionNumber).toBe(1) // column B, 0-based
    expect(result?.columns.componentLabel).toBe(3) // column D
    expect(result?.columns.unitCostAw).toBe(8) // column I
  })

  it('returns null when no componentLabel + cost column pair is found', () => {
    const grid = gridFromCells({ B1: 'Irgendwas', C1: 'Noch was' })
    const input: MaterialMatrixGridInput = { sheet: 'Irrelevant', grid }
    expect(locateMaterialMatrixHeader(input, 0, 10, 1, 10)).toBeNull()
  })
})

// ── parseMaterialMatrix — header-not-found ──────────────────────────────

describe('parseMaterialMatrix — header not found', () => {
  it('returns an empty result with a warning when the sheet has no usable header', async () => {
    const grid = gridFromCells({ A1: 'Nothing here' })
    const input: MaterialMatrixGridInput = { sheet: 'Empty Sheet', grid }
    const result = await parseMaterialMatrix(input, [V1])
    expect(result.rows).toEqual([])
    expect(result.reconciliation).toEqual([])
    expect(result.headerRow).toBeNull()
    expect(result.warnings.map((w) => w.code)).toContain('material_matrix_header_not_found')
  })
})

// ── parseMaterialMatrix — row extraction ────────────────────────────────

describe('parseMaterialMatrix — row extraction', () => {
  let result: MaterialMatrixParseResult

  beforeAll(async () => {
    const input = buildPrimaryGrid()
    result = await parseMaterialMatrix(input, [V1, V2, V3, V4])
  })

  it('extracts one row per real material position, skipping the padding row and the labeled total row', () => {
    // 4 distinct positions (1,2,3,4) + 1 duplicate (pos 1 again) = 5 rows;
    // row 9 (padding) and row 12 (labeled total row, KAR-931 F1) skipped.
    expect(result.rows).toHaveLength(5)
    expect(result.rows.map((r) => r.sourceRow)).toEqual([6, 7, 8, 10, 11])
    expect(result.rows.some((r) => r.sourceRow === 12)).toBe(false)
  })

  it('omits a variant key entirely for a BLANK cell (not applicable), includes an explicit literal 0', () => {
    const sensorB = result.rows.find((r) => r.sourceRow === 7)!
    expect(sensorB.quantityFactorByVariant['variant-alpha']).toBe(2)
    expect(sensorB.quantityFactorByVariant['variant-beta']).toBeUndefined() // blank cell -> omitted, not 0.
    expect('variant-beta' in sensorB.quantityFactorByVariant).toBe(false)
    expect(sensorB.quantityFactorByVariant['variant-gamma']).toBe(12)

    const screwC = result.rows.find((r) => r.sourceRow === 8)!
    expect(screwC.quantityFactorByVariant['variant-alpha']).toBe(0) // explicit literal 0 -> included.
    expect('variant-alpha' in screwC.quantityFactorByVariant).toBe(true)
    expect(screwC.quantityFactorByVariant['variant-gamma']).toBeUndefined() // blank -> omitted.
  })

  it('computes effectiveCostByVariant = unitCost x factor for present entries', () => {
    const gasketD = result.rows.find((r) => r.sourceRow === 11)!
    expect(gasketD.quantityFactorByVariant['variant-alpha']).toBe(28) // real factor-diversity value from the corpus.
    expect(gasketD.effectiveCostByVariant['variant-alpha']).toBe(2 * 28)
    expect(gasketD.effectiveCostByVariant['variant-beta']).toBe(2 * 0)
    expect('variant-gamma' in gasketD.effectiveCostByVariant).toBe(false)
  })

  it('reproduces the real factor-diversity range (0/1/2/12/28/71) across the matrix', () => {
    const allFactors = result.rows.flatMap((r) => Object.values(r.quantityFactorByVariant))
    expect(new Set(allFactors)).toEqual(new Set([1, 2, 0, 12, 71, 28]))
  })

  it('deterministically disambiguates a split/collision row sharing position+label with an earlier row using a stable ordinal, not the raw row number (KAR-931 F4)', () => {
    const [bracketA1, bracketA2] = result.rows.filter((r) => r.sourceRow === 6 || r.sourceRow === 10)
    expect(bracketA1.canonicalComponentIdentity).not.toBe(bracketA2.canonicalComponentIdentity)
    expect(bracketA2.canonicalComponentIdentity).toContain('#2')
    expect(bracketA2.canonicalComponentIdentity).not.toContain('#row10')
    expect(bracketA2.validationStatus).toBe('needs_review')
    expect(result.warnings.map((w) => w.code)).toContain('material_matrix_row_identity_collision')
  })

  it('flags the padding row as a skipped, harmless #DIV/0! pattern (info warning, not a data row)', () => {
    expect(result.rows.some((r) => r.sourceRow === 9)).toBe(false)
    const paddingWarning = result.warnings.find((w) => w.code === 'material_matrix_padding_rows_skipped')
    expect(paddingWarning).toBeDefined()
    expect(paddingWarning?.severity).toBe('info')
  })

  it('flags the labeled total row as recognized+excluded (KAR-931 F1), not silently absorbed', () => {
    const totalWarning = result.warnings.find((w) => w.code === 'material_matrix_total_row_excluded')
    expect(totalWarning).toBeDefined()
    expect(totalWarning?.severity).toBe('info')
  })

  it('marks validationStatus ok for a clean row with at least one factor and known unit cost', () => {
    const bracketA1 = result.rows.find((r) => r.sourceRow === 6)!
    expect(bracketA1.validationStatus).toBe('ok')
    expect(bracketA1.unitCost).toEqual({ value: 10, currency: 'EUR' })
  })
})

describe('parseMaterialMatrix — degraded rows', () => {
  it('marks missing_unit_cost when the AW column is blank for a real row', async () => {
    const grid = gridFromCells({
      ...HEADER_CELLS,
      B6: '1',
      D6: 'Bracket A',
      F6: 'EUR',
      // I6 (unitCostAw) deliberately omitted.
      N6: 1,
    })
    const input: MaterialMatrixGridInput = { sheet: 'Material', grid }
    const result = await parseMaterialMatrix(input, [V1])
    expect(result.rows[0].validationStatus).toBe('missing_unit_cost')
    expect(result.rows[0].unitCost.value).toBeNull()
  })

  it('marks formula_error_cached when the AW cell itself holds an Excel error literal', async () => {
    const grid = gridFromCells({
      ...HEADER_CELLS,
      B6: '1',
      D6: 'Bracket A',
      F6: 'EUR',
      I6: '#REF!',
      N6: 1,
    })
    const input: MaterialMatrixGridInput = { sheet: 'Material', grid }
    const result = await parseMaterialMatrix(input, [V1])
    expect(result.rows[0].validationStatus).toBe('formula_error_cached')
    expect(result.rows[0].unitCost.value).toBeNull()
  })

  it('marks missing_factor_for_all_variants when no variant column carries a value', async () => {
    const grid = gridFromCells({
      ...HEADER_CELLS,
      B6: '1',
      D6: 'Bracket A',
      F6: 'EUR',
      I6: 10,
      // N6/O6/P6 all blank.
    })
    const input: MaterialMatrixGridInput = { sheet: 'Material', grid }
    const result = await parseMaterialMatrix(input, [V1, V2, V3])
    expect(result.rows[0].validationStatus).toBe('missing_factor_for_all_variants')
  })
})

// ── KAR-931 adversarial-review fix F1: total-/summary-row detection ─────

describe('parseMaterialMatrix — total-/summary-row detection (KAR-931 F1)', () => {
  it('excludes a labeled total row with no aggregate formula (label-pattern-only detection)', async () => {
    const grid = gridFromCells({
      ...HEADER_CELLS,
      B6: '1',
      D6: 'Bracket A',
      F6: 'EUR',
      I6: 10,
      N6: 1,
      // Row 7: "Gesamt" label, no position, no formula at all — label-pattern
      // detection alone must exclude it.
      D7: 'Gesamt',
      N7: 999,
    })
    const input: MaterialMatrixGridInput = { sheet: 'Material', grid }
    const result = await parseMaterialMatrix(input, [V1])
    expect(result.rows).toHaveLength(1)
    expect(result.rows[0].sourceRow).toBe(6)
    expect(result.warnings.map((w) => w.code)).toContain('material_matrix_total_row_excluded')
  })

  it('excludes an unlabeled aggregate-formula row even without a Summe/Gesamt/Total label (formula-shape-only detection)', async () => {
    const grid = gridFromCells({
      ...HEADER_CELLS,
      B6: '1',
      D6: 'Bracket A',
      F6: 'EUR',
      I6: 10,
      N6: 1,
      // Row 7: no label, no position, but a SUMPRODUCT formula in the
      // variant column — formula-shape detection alone must exclude it.
      N7: 999,
    })
    const formulaGrid = formulaGridFromCells({ N7: '=SUMPRODUCT($I$6:$I$6,N6:N6)' })
    const input: MaterialMatrixGridInput = { sheet: 'Material', grid, formulaGrid }
    const result = await parseMaterialMatrix(input, [V1])
    expect(result.rows).toHaveLength(1)
    expect(result.rows[0].sourceRow).toBe(6)
  })

  it('does NOT exclude a genuine material row whose label is a German compound word starting with the "Summe" token (word-boundary-safe)', async () => {
    const grid = gridFromCells({
      ...HEADER_CELLS,
      B6: '1',
      D6: 'Summenzahnrad', // a (invented) compound word starting with "Summen..." — NOT the standalone total-row token "Summe".
      F6: 'EUR',
      I6: 10,
      N6: 1,
    })
    const input: MaterialMatrixGridInput = { sheet: 'Material', grid }
    const result = await parseMaterialMatrix(input, [V1])
    // TOTAL_ROW_LABEL_RE anchors on a WORD boundary right after the token
    // ("summe\b") — "Summenzahnrad" continues past "Summe" with another word
    // character ("n"), so no boundary exists there and the label-pattern
    // match correctly fails. This row has a position number and a factor
    // too, so it is kept as a genuine material row either way.
    expect(result.rows).toHaveLength(1)
    expect(result.rows[0].sourceRow).toBe(6)
    expect(result.warnings.map((w) => w.code)).not.toContain('material_matrix_total_row_excluded')
  })
})

// ── SUMPRODUCT-Verifikation ──────────────────────────────────────────────

describe('parseMaterialMatrix — SUMPRODUCT reconciliation', () => {
  let result: MaterialMatrixParseResult

  beforeAll(async () => {
    const input = buildPrimaryGrid()
    result = await parseMaterialMatrix(input, [V1, V2, V3, V4])
  })

  it('reports bestanden for a variant whose independently recomputed sum matches the sheet total', () => {
    const alpha = result.reconciliation.find((r) => r.variantId === 'variant-alpha')!
    expect(alpha.status).toBe('bestanden')
    expect(alpha.expected).toBe(86)
    expect(alpha.actual).toBe(86)

    const beta = result.reconciliation.find((r) => r.variantId === 'variant-beta')!
    expect(beta.status).toBe('bestanden')
    expect(beta.expected).toBe(91)
  })

  it('reports abweichung when the recomputed sum diverges from the sheet total beyond tolerance', () => {
    const gamma = result.reconciliation.find((r) => r.variantId === 'variant-gamma')!
    expect(gamma.status).toBe('abweichung')
    expect(gamma.expected).toBe(80)
    expect(gamma.actual).toBe(100)
    expect(gamma.deltaAbsolute).toBe(20)
  })

  it('reports nicht_pruefbar when no SUMIF/SUMPRODUCT/aggregate total formula is found for a variant', () => {
    const delta = result.reconciliation.find((r) => r.variantId === 'variant-delta')!
    expect(delta.status).toBe('nicht_pruefbar')
    expect(delta.reason).toBeDefined()
    expect(delta.totalCell).toBeNull()
  })

  it('reports nicht_pruefbar when a row carries a factor but no known unit cost for that variant', async () => {
    const grid = gridFromCells({
      ...HEADER_CELLS,
      B6: '1',
      D6: 'Bracket A',
      F6: 'EUR',
      // I6 omitted -> unitCost.value null for this row.
      N6: 1,
      N7: 999, // total row cached value (irrelevant — blocked before comparison).
    })
    const formulaGrid = formulaGridFromCells({ N7: '=SUM(N6:N6)' })
    const input2: MaterialMatrixGridInput = { sheet: 'Material', grid, formulaGrid }
    const result2 = await parseMaterialMatrix(input2, [V1])
    const alpha = result2.reconciliation[0]
    expect(alpha.status).toBe('nicht_pruefbar')
    expect(alpha.reason).toMatch(/Einheitskosten/)
  })
})

// ── formula_column_range_inconsistency (range-defect pattern (10-analyse-clarwe-eu.md) — detected, not
// reproduced) ────────────────────────────────────────────────────────────

describe('parseMaterialMatrix — row-control-column range inconsistency', () => {
  it('flags a warning when the average-factor and sum-factor control columns span different widths', async () => {
    const grid = gridFromCells({
      ...HEADER_CELLS,
      B6: '1',
      D6: 'Bracket A',
      F6: 'EUR',
      I6: 10,
      N6: 1,
      O6: 1,
      L6: 1, // AVERAGE control column cached value
      M6: 1, // SUM control column cached value
    })
    const formulaGrid = formulaGridFromCells({
      L6: '=AVERAGE(N6:O6)', // spans 2 columns
      M6: '=SUMIF(N6:P6,">0",N6:P6)', // spans 3 columns — inconsistent with L6.
    })
    const input: MaterialMatrixGridInput = { sheet: 'Material', grid, formulaGrid }
    const result = await parseMaterialMatrix(input, [V1, V2, V3])
    expect(result.warnings.map((w) => w.code)).toContain('formula_column_range_inconsistency')
  })

  it('does not flag anything when the control columns agree (or are absent)', async () => {
    const input = buildPrimaryGrid() // has L/M header labels but no L/M formulas at the first material row.
    const result = await parseMaterialMatrix(input, [V1, V2, V3, V4])
    expect(result.warnings.map((w) => w.code)).not.toContain('formula_column_range_inconsistency')
  })
})

// ── Performance guard (fail-closed truncation, KAR-931 F2 fix) ──────────

describe('parseMaterialMatrix — performance guard', () => {
  it('marks the result truncated and downgrades reconciliation to nicht_pruefbar when the scan window edge is reached with plausible content', async () => {
    const grid = gridFromCells({
      ...HEADER_CELLS,
      B6: '1',
      D6: 'Bracket A',
      F6: 'EUR',
      I6: 10,
      N6: 1,
      B7: '2', // still carries a position number AT the artificially tiny rowTo boundary (row 7).
      D7: 'Sensor B',
      I7: 5,
      N7: 1,
    })
    const input: MaterialMatrixGridInput = { sheet: 'Material', grid }
    const result = await parseMaterialMatrix(input, [V1], { rowTo: 7 })
    expect(result.truncated).toBe(true)
    expect(result.warnings.map((w) => w.code)).toContain('material_matrix_scan_truncated')
    expect(result.reconciliation[0].status).toBe('nicht_pruefbar')
    expect(result.reconciliation[0].reason).toMatch(/Performance-Guard/)
  })

  it('does not mark truncated when the real data ends well before the scan window edge', async () => {
    const input = buildPrimaryGrid()
    const result = await parseMaterialMatrix(input, [V1, V2, V3, V4])
    expect(result.truncated).toBe(false)
  })

  it('does NOT flag truncation when the window edge lands on a genuinely blank template row (KAR-931 F2)', async () => {
    const grid = gridFromCells({
      ...HEADER_CELLS,
      B6: '1',
      D6: 'Bracket A',
      F6: 'EUR',
      I6: 10,
      N6: 1,
      // Row 7 is entirely blank — a template artifact row, not data — and is
      // also the exact rowTo boundary below. A6-referencing null cell only
      // extends the grid's row dimension to include row 7 at all (gridFromCells
      // sizes the grid by the highest referenced row); every other column in
      // that row is already null-filled by construction.
      A7: null,
    })
    const input: MaterialMatrixGridInput = { sheet: 'Material', grid }
    const result = await parseMaterialMatrix(input, [V1], { rowTo: 7 })
    expect(result.truncated).toBe(false)
    expect(result.warnings.map((w) => w.code)).not.toContain('material_matrix_scan_truncated')
  })

  it('does NOT flag truncation when the window edge lands exactly on a recognized total row (KAR-931 F2 — the materialMatrixScanBoundsFromWorksheet real-world case)', async () => {
    const grid = gridFromCells({
      ...HEADER_CELLS,
      B6: '1',
      D6: 'Bracket A',
      F6: 'EUR',
      I6: 10,
      N6: 1,
      // Row 7 is the recognized total row (label-pattern match) AND is the
      // exact rowTo boundary — mirrors materialMatrixScanBoundsFromWorksheet
      // feeding rowTo = the sheet's own last populated row, which for a
      // complete file is usually the total row itself.
      D7: 'Summe Materialkosten',
      N7: 10,
    })
    const input: MaterialMatrixGridInput = { sheet: 'Material', grid }
    const result = await parseMaterialMatrix(input, [V1], { rowTo: 7 })
    expect(result.truncated).toBe(false)
    expect(result.warnings.map((w) => w.code)).not.toContain('material_matrix_scan_truncated')
    expect(result.warnings.map((w) => w.code)).toContain('material_matrix_total_row_excluded')
  })
})

// ── KAR-931 adversarial-review fix F4: row-shift invariance of the
// collision-disambiguation identity ─────────────────────────────────────

describe('parseMaterialMatrix — collision identity row-shift invariance (KAR-931 F4)', () => {
  function buildCollisionGrid(extraRowOffset: number): MaterialMatrixGridInput {
    // Base layout: pos-1 duplicate at rows 6 and 10 (matches buildPrimaryGrid
    // above). `extraRowOffset` inserts that many additional unrelated rows
    // ABOVE row 10 (between the two occurrences) — same collision GROUP
    // order preserved, only the second occurrence's absolute row shifts.
    const cells: Record<string, unknown> = {
      ...HEADER_CELLS,
      B6: '1',
      D6: 'Bracket A',
      F6: 'EUR',
      I6: 10,
      N6: 1,
    }
    const secondRow = 10 + extraRowOffset
    for (let r = 7; r < secondRow; r++) {
      // Unrelated filler material rows (distinct positions) inserted above
      // the second occurrence — never collide with pos "1".
      cells[`B${r}`] = String(r)
      cells[`D${r}`] = `Filler ${r}`
      cells[`F${r}`] = 'EUR'
      cells[`I${r}`] = 1
      cells[`N${r}`] = 1
    }
    cells[`B${secondRow}`] = '1'
    cells[`D${secondRow}`] = 'Bracket A'
    cells[`F${secondRow}`] = 'EUR'
    cells[`I${secondRow}`] = 10
    cells[`N${secondRow}`] = 1
    return { sheet: 'Material', grid: gridFromCells(cells) }
  }

  it('assigns the SAME collision-ordinal identity to the duplicate row regardless of an unrelated row inserted above it', async () => {
    const versionA = buildCollisionGrid(0) // duplicate at row 10, no filler rows
    const versionB = buildCollisionGrid(5) // duplicate shifted to row 15 by 5 inserted filler rows above it

    const resultA = await parseMaterialMatrix(versionA, [V1])
    const resultB = await parseMaterialMatrix(versionB, [V1])

    const dupA = resultA.rows.find((r) => r.canonicalComponentIdentity.includes('#'))!
    const dupB = resultB.rows.find((r) => r.canonicalComponentIdentity.includes('#'))!

    expect(dupA).toBeDefined()
    expect(dupB).toBeDefined()
    expect(dupA.sourceRow).toBe(10)
    expect(dupB.sourceRow).toBe(15) // absolute row DID shift...
    expect(dupA.canonicalComponentIdentity).toBe(dupB.canonicalComponentIdentity) // ...identity did NOT.
  })
})

// ── KAR-931 adversarial-review fix F3: canonical-registry label resolution
// (single source of truth, no hand-copied literal) ───────────────────────

describe('parseMaterialMatrix — canonical MATERIAL-registry label resolution (KAR-931 F3)', () => {
  function buildCanonicalLabelGrid(unitCostAwLabel: string): MaterialMatrixGridInput {
    const cells: Record<string, unknown> = {
      // Canonical MATERIAL-sheet registry labels (not the bespoke Multi-QAF
      // labels in HEADER_CELLS above) — this module deliberately reuses
      // these 3 from the standard MATERIAL sheet's registry entries.
      B5: 'Positionsnummer Fertigungsschritt',
      D5: 'Benennung Rohmaterial / Kaufteil',
      I5: unitCostAwLabel,
      B6: '1',
      D6: 'Bracket A',
      I6: 10,
      N6: 1,
    }
    return { sheet: 'Material', grid: gridFromCells(cells) }
  }

  it('resolves unitCostAw via the KAR-915-confirmed real V8.8 alias "Materialkosten [AW]"', async () => {
    const input = buildCanonicalLabelGrid('Materialkosten [AW]')
    const result = await parseMaterialMatrix(input, [V1])
    expect(result.headerRow).not.toBeNull()
    expect(result.rows).toHaveLength(1)
    expect(result.rows[0].unitCost.value).toBe(10)
  })

  it('resolves unitCostAw via the stale/historical labelDe "Kalkulatorische Materialkosten [AW]" too (registry still carries it as the primary label)', async () => {
    const input = buildCanonicalLabelGrid('Kalkulatorische Materialkosten [AW]')
    const result = await parseMaterialMatrix(input, [V1])
    expect(result.headerRow).not.toBeNull()
    expect(result.rows).toHaveLength(1)
    expect(result.rows[0].unitCost.value).toBe(10)
  })

  it('resolves positionNumber/componentLabel via the canonical MATERIAL-registry labels, not a hand-copied local constant', async () => {
    const input = buildCanonicalLabelGrid('Materialkosten [AW]')
    const result = await parseMaterialMatrix(input, [V1])
    expect(result.rows[0].sourceRow).toBe(6)
    expect(result.rows[0].canonicalComponentIdentity.startsWith('1::')).toBe(true)
  })
})
