// KAR-940 adversarial review F3 — structural regression test.
//
// Bug: `reconcileContainer` called `reconcileVirtualVariant` once per
// variant, and EACH call independently re-derived `reconciliationEntries`
// (profile-differ.ts, which itself calls `generateVirtualVariants`) and the
// `allProfiles`/`profileById` map from scratch — O(N) work times N variants
// = O(N²) for a container with N variants, not the module header's
// documented O(N).
//
// Fix: `reconcileContainer` now builds ONE `VariantReconciliationContext`
// (`buildReconciliationContext`) per container and threads it through every
// variant's `reconcileVirtualVariant` call via an optional 4th parameter;
// `reconcileVirtualVariant` keeps its standalone signature (builds its own
// context when none is passed).
//
// This file mocks profile-differ.ts's exported `reconciliationEntries`
// (wrapping the REAL implementation in `vi.fn` so behavior is unchanged,
// only call-counted) to structurally prove the once-per-container claim —
// isolated in its own file (Vitest resets the module registry per test
// file) so the mock never touches variant-reconciliation.test.ts's 1000+
// lines of behavior assertions.
//
// tdd-guard:skip — structural/call-count regression test, not a unit-level
// behavior spec (behavior is unit-tested in variant-reconciliation.test.ts).

import { describe, it, expect, vi } from "vitest"

vi.mock("../profile-differ", async (importOriginal) => {
  const actual = await importOriginal<typeof import("../profile-differ")>()
  return {
    ...actual,
    reconciliationEntries: vi.fn(actual.reconciliationEntries),
  }
})

import { buildCompositeCanonicalKey, makeDimensionValue } from "../identity"
import type {
  MultiQafContainer,
  VariantDefinition,
  VariantDimensions,
  VirtualQafVariant,
} from "../types"
import {
  reconcileContainer,
  reconcileVirtualVariant,
} from "../variant-reconciliation"
import { reconciliationEntries } from "../profile-differ"

// ── Minimal fixture builders (mirrors variant-reconciliation.test.ts's own
// local builders — established per-test-file duplication precedent in this
// package, not shared; only what THIS file needs). ─────────────────────────

const DEFAULT_TEST_FINGERPRINT = "test-container-fingerprint"

function dims(entries: Record<string, string>): VariantDimensions {
  const out: Record<string, ReturnType<typeof makeDimensionValue>> = {}
  for (const [k, v] of Object.entries(entries)) out[k] = makeDimensionValue(v)
  return out
}

function variant(
  id: string,
  overrides: Partial<VariantDefinition> = {}
): VariantDefinition {
  const dimensions = overrides.dimensions ?? dims({ region: "EU" })
  const labels = overrides.originalLabels ?? [`Label ${id}`]
  return {
    stableInternalId: id,
    originalColumn: overrides.originalColumn ?? "Q",
    originalColumnIndex: overrides.originalColumnIndex ?? 17,
    originalVariantNumber: overrides.originalVariantNumber ?? "1",
    originalLabels: labels,
    normalizedLabels:
      overrides.normalizedLabels ?? labels.map((l) => l.toLowerCase()),
    compositeCanonicalKey:
      overrides.compositeCanonicalKey ??
      buildCompositeCanonicalKey(dimensions, id),
    dimensions,
    annualVolume: overrides.annualVolume ?? 1000,
    peakVolume: overrides.peakVolume ?? null,
    lifetimeVolume: overrides.lifetimeVolume ?? null,
    currency: overrides.currency !== undefined ? overrides.currency : "EUR",
    activeState: overrides.activeState ?? "active",
    sourceReferences: overrides.sourceReferences ?? [
      {
        sheet: "Zusammenfassung",
        cell: `${overrides.originalColumn ?? "Q"}2`,
        row: 1,
        column: overrides.originalColumnIndex ?? 17,
      },
    ],
    confidence: overrides.confidence ?? 0.9,
  }
}

function emptyContainer(
  overrides: Partial<MultiQafContainer> = {}
): MultiQafContainer {
  return {
    sourceWorkbook: {
      fileName: null,
      fileHash: null,
      sheetNames: [],
      hiddenSheetNames: [],
    },
    detectedTemplateFamily: "unknown",
    multiQafVersion: null,
    underlyingQafVersion: null,
    language: "unknown",
    currencies: [],
    sharedMetadata: {},
    variantDimensions: [],
    activeVariants: [],
    inactiveVariants: [],
    auxiliaryScenarios: [],
    helperColumns: [],
    sharedMaterialMaster: [],
    sharedManufacturingProfiles: [],
    sharedToolingData: [],
    setupCostProfiles: [],
    variantProfileBindings: [],
    summaryAggregation: { perVariant: [], formulaLineageNotes: [] },
    templateFingerprint: {
      family: "unknown",
      structuralHash: DEFAULT_TEST_FINGERPRINT,
      variantColumnCount: 0,
      headerRowCount: 0,
      knownProfile: null,
      classification: null,
    },
    warnings: [],
    confidence: 0.5,
    summaryMoneyRowsByVariant: {},
    ...overrides,
  }
}

describe("KAR-940 F3 — shared per-container context, not re-derived per variant", () => {
  it("reconcileContainer calls reconciliationEntries exactly ONCE for a 3-variant container (not once per variant — the O(N²) bug)", () => {
    const container = emptyContainer({
      activeVariants: [variant("V1"), variant("V2"), variant("V3")],
    })
    const before = vi.mocked(reconciliationEntries).mock.calls.length

    const results = reconcileContainer(container)

    expect(results).toHaveLength(3)
    const callsMade = vi.mocked(reconciliationEntries).mock.calls.length - before
    expect(callsMade).toBe(1)
  })

  it("scales the same way for a 10-variant container — still exactly ONE call, not 10", () => {
    const container = emptyContainer({
      activeVariants: Array.from({ length: 10 }, (_, i) => variant(`V${i}`)),
    })
    const before = vi.mocked(reconciliationEntries).mock.calls.length

    const results = reconcileContainer(container)

    expect(results).toHaveLength(10)
    const callsMade = vi.mocked(reconciliationEntries).mock.calls.length - before
    expect(callsMade).toBe(1)
  })

  it("reconcileVirtualVariant called standalone (no context passed) still self-builds — N standalone calls make N reconciliationEntries calls, contrasted with reconcileContainer's ONE for the identical variant set", () => {
    const container = emptyContainer({
      activeVariants: [variant("V1"), variant("V2")],
    })
    const vv1: VirtualQafVariant = {
      variantId: "V1",
      containerFingerprint: DEFAULT_TEST_FINGERPRINT,
      definition: variant("V1"),
      materialRows: [],
      selectedManufacturingProfile: null,
      selectedSetupCostProfile: null,
      selectedToolingProfile: null,
      summaryTotals: {
        variantId: "V1",
        materialCosts: null,
        materialCostsByCurrency: [],
        manufacturingCosts: null,
        totalProductionCosts: null,
        toolingAndFixtureCost: null,
        setupCostAllocation: null,
        scrap: null,
        otherSurcharges: null,
        offerBasePrice: null,
        offerBasePriceInclAllocation: null,
        offerPrice: null,
      },
      warnings: [],
    }
    const vv2: VirtualQafVariant = { ...vv1, variantId: "V2", definition: variant("V2") }

    // Standalone: the module header's own documented fallback behavior —
    // reconcileVirtualVariant() without a context builds its own every time.
    const beforeStandalone = vi.mocked(reconciliationEntries).mock.calls.length
    reconcileVirtualVariant(vv1, container)
    reconcileVirtualVariant(vv2, container)
    const standaloneCalls =
      vi.mocked(reconciliationEntries).mock.calls.length - beforeStandalone
    expect(standaloneCalls).toBe(2)

    // The SAME two variants via reconcileContainer: exactly ONE call — the
    // KAR-940 F3 fix (shared VariantReconciliationContext threaded through).
    const beforeContainer = vi.mocked(reconciliationEntries).mock.calls.length
    reconcileContainer(container)
    const containerCalls =
      vi.mocked(reconciliationEntries).mock.calls.length - beforeContainer
    expect(containerCalls).toBe(1)
  })
})
