import { describe, it, expect } from 'vitest'
import {
  benchmarkVariantsFromVirtualVariants,
  benchmarkVariantsFromSummaryMetrics,
  type VirtualVariantTotalsLike,
  type SummaryMetricRowLike,
} from '../benchmark-input'
import { buildSupplierBenchmark } from '../supplier-benchmark'

const eur = (value: number) => ({ value, currency: 'EUR' })
const usd = (value: number) => ({ value, currency: 'USD' })

function totals(o: Partial<VirtualVariantTotalsLike['summaryTotals']> = {}): VirtualVariantTotalsLike['summaryTotals'] {
  return {
    materialCosts: null,
    manufacturingCosts: null,
    totalProductionCosts: null,
    toolingAndFixtureCost: null,
    setupCostAllocation: null,
    scrap: null,
    otherSurcharges: null,
    offerBasePrice: null,
    offerPrice: null,
    ...o,
  }
}

describe('Multi-QAF-Container → Benchmark-Eingabe', () => {
  it('hängt die Positionen je Variante um, ohne Werte zu ersetzen', () => {
    const variants: VirtualVariantTotalsLike[] = [
      { variantId: 'V1', summaryTotals: totals({ materialCosts: eur(180), totalProductionCosts: eur(209) }) },
      { variantId: 'V2', summaryTotals: totals({ materialCosts: eur(195), totalProductionCosts: eur(224) }) },
    ]
    const out = benchmarkVariantsFromVirtualVariants(variants)
    expect(out).toHaveLength(2)
    expect(out[0].variantId).toBe('V1')
    expect(out[0].materialCosts).toEqual(eur(180))
    expect(out[1].totalProductionCosts).toEqual(eur(224))
  })

  it('lässt null null — es wird nichts auf 0 gesetzt', () => {
    const out = benchmarkVariantsFromVirtualVariants([{ variantId: 'V1', summaryTotals: totals() }])
    expect(out[0].materialCosts).toBeNull()
    expect(out[0].offerPrice).toBeNull()
    expect(out[0].scrap).toBeNull()
  })

  it('liefert für einen leeren Container eine leere Liste, nicht einen leeren Eintrag', () => {
    expect(benchmarkVariantsFromVirtualVariants([])).toEqual([])
  })
})

describe('Standard-Summary-Metriken → Benchmark-Eingabe', () => {
  const rows: SummaryMetricRowLike[] = [
    { metric_key: 'materialCosts', currency: 'EUR', value: 180 },
    { metric_key: 'manufacturingCosts', currency: 'EUR', value: 29 },
    { metric_key: 'totalProductionCosts', currency: 'EUR', value: 209 },
    { metric_key: 'quotationBasePrice', currency: 'EUR', value: 258 },
    { metric_key: 'quotationPrice', currency: 'EUR', value: 335 },
  ]

  it('ergibt genau EINE Variante — ein Standard-QAF beschreibt einen Umfang', () => {
    const out = benchmarkVariantsFromSummaryMetrics(rows)
    expect(out).toHaveLength(1)
    expect(out[0].variantId).toBe('standard')
  })

  it('mappt die Positionen auf die Benchmark-Felder', () => {
    const [v] = benchmarkVariantsFromSummaryMetrics(rows)
    expect(v.materialCosts).toEqual(eur(180))
    expect(v.manufacturingCosts).toEqual(eur(29))
    expect(v.totalProductionCosts).toEqual(eur(209))
    expect(v.offerBasePrice).toEqual(eur(258))
    expect(v.offerPrice).toEqual(eur(335))
  })

  it('addiert die zwei Ausschuss-Hälften nur bei gleicher Währung', () => {
    const same = benchmarkVariantsFromSummaryMetrics([
      ...rows,
      { metric_key: 'scrapMaterial', currency: 'EUR', value: 1.7 },
      { metric_key: 'scrapManufacturing', currency: 'EUR', value: 1.0 },
    ])
    expect(same[0].scrap).toEqual({ value: 2.7, currency: 'EUR' })
  })

  it('verweigert die Ausschuss-Summe über Währungsgrenzen statt sie zu bilden', () => {
    const mixed = benchmarkVariantsFromSummaryMetrics([
      ...rows,
      { metric_key: 'scrapMaterial', currency: 'EUR', value: 1.7 },
      { metric_key: 'scrapManufacturing', currency: 'USD', value: 1.0 },
    ])
    // Eine Summe wäre hier eine stille Fehlzahl — lieber nicht ermittelbar.
    expect(mixed[0].scrap).toBeNull()
  })

  it('übernimmt eine einzeln vorhandene Ausschuss-Hälfte, statt sie zu verwerfen', () => {
    const onlyMaterial = benchmarkVariantsFromSummaryMetrics([
      ...rows,
      { metric_key: 'scrapMaterial', currency: 'EUR', value: 1.7 },
    ])
    expect(onlyMaterial[0].scrap).toEqual(eur(1.7))
  })

  it('überspringt unbekannte metric_key-Werte, statt daran zu scheitern', () => {
    const withUnknown = benchmarkVariantsFromSummaryMetrics([
      ...rows,
      { metric_key: 'someFutureMetric', currency: 'EUR', value: 42 },
    ])
    expect(withUnknown[0].materialCosts).toEqual(eur(180))
  })

  it('überspringt Zeilen ohne Wert', () => {
    const out = benchmarkVariantsFromSummaryMetrics([{ metric_key: 'materialCosts', currency: 'EUR', value: null }])
    expect(out[0].materialCosts).toBeNull()
  })
})

describe('Multi-QAF gegen Standard — der format-gemischte Fall', () => {
  it('rechnet beide Seiten, obwohl eine 3 Varianten und die andere 1 hat', () => {
    const container = benchmarkVariantsFromVirtualVariants([
      { variantId: 'V1', summaryTotals: totals({ materialCosts: usd(240), totalProductionCosts: usd(284), offerBasePrice: usd(340), offerPrice: usd(342) }) },
      { variantId: 'V2', summaryTotals: totals({ materialCosts: usd(250), totalProductionCosts: usd(300), offerBasePrice: usd(360), offerPrice: usd(362) }) },
      { variantId: 'V3', summaryTotals: totals({ materialCosts: usd(280), totalProductionCosts: usd(322), offerBasePrice: usd(388), offerPrice: usd(390) }) },
    ])
    const standard = benchmarkVariantsFromSummaryMetrics([
      { metric_key: 'materialCosts', currency: 'EUR', value: 180 },
      { metric_key: 'totalProductionCosts', currency: 'EUR', value: 209 },
      { metric_key: 'quotationBasePrice', currency: 'EUR', value: 258 },
      { metric_key: 'quotationPrice', currency: 'EUR', value: 335 },
    ])

    const r = buildSupplierBenchmark(
      { label: 'Container', variants: container },
      { label: 'Standard', variants: standard }
    )

    expect(r.left.variantCount).toBe(3)
    expect(r.right.variantCount).toBe(1)
    // Beide Seiten liefern eine vergleichbare Kennzahl — genau der Punkt des
    // matching-freien Designs.
    expect(r.left.costStructure.materialShareOfProduction.median).not.toBeNull()
    expect(r.right.costStructure.materialShareOfProduction.median).not.toBeNull()
    // Standard-Seite: eine Variante -> Median = min = max
    const m = r.right.costStructure.materialShareOfProduction
    expect(m.median).toBe(m.min)
    expect(m.median).toBe(m.max)
    // Der Aufschlag-Befund bleibt über den Formatwechsel lesbar
    expect(r.left.markupChain.offerBaseToOfferPrice.median).toBeLessThan(0.02)
    expect(r.right.markupChain.offerBaseToOfferPrice.median).toBeGreaterThan(0.25)
    // Verschiedene Währungen der Seiten werden gemeldet
    expect(r.notices.some((n) => n.kind === 'currencies_differ_between_sides')).toBe(true)
  })
})
