// A5 Bestandsreichweite / Little's Law (§8.5) — hand-calculated tests.
// FIXTURE-DATEN-REGEL: every number below is FREE INVENTION.

import { describe, expect, it } from 'vitest'
import { computeInventoryCoverage } from '../internal/inventory-coverage'
import type { ShiftModelInput } from '../internal/work-time'

describe('computeInventoryCoverage', () => {
  it('hand calc: 1500 pcs at 500 pcs/day -> 3 days coverage (no shift model -> no shifts/hours/min)', () => {
    const result = computeInventoryCoverage(1500, { unitsPerDay: 500 })
    expect(result.coverageDays).toBe(3)
    expect(result.coverageShifts).toBeNull()
    expect(result.coverageHours).toBeNull()
    expect(result.coverageMin).toBeNull()
  })

  it('hand calc: same 3 days, WITH an 8h/2-shift/30min-break shift model -> 45h / 2700min / 6 shifts', () => {
    // netSecPerShift = 8*3600-1800 = 27000; netSecPerDay = 54000.
    // totalCoverageSec = 3 days * 54000 = 162000 -> 45h, 2700min. coverageShifts = 3*2 = 6.
    const shiftModel: ShiftModelInput = { hoursPerShift: 8, shiftsPerDay: 2, breakMinPerShift: 30 }
    const result = computeInventoryCoverage(1500, { unitsPerDay: 500 }, shiftModel)
    expect(result.coverageDays).toBe(3)
    expect(result.coverageShifts).toBe(6)
    expect(result.coverageHours).toBe(45)
    expect(result.coverageMin).toBe(2700)
  })

  it('a genuine 0 quantity computes to coverageDays: 0 (a real measured zero, NOT "unknown")', () => {
    const result = computeInventoryCoverage(0, { unitsPerDay: 500 })
    expect(result.coverageDays).toBe(0)
    expect(result.quantity).toBe(0)
  })

  it('an undefined quantity is "unknown" (null), distinct from the genuine-zero case above', () => {
    const result = computeInventoryCoverage(undefined, { unitsPerDay: 500 })
    expect(result.coverageDays).toBeNull()
    expect(result.quantity).toBeNull()
  })

  it('returns null (never Infinity) when the demand rate is 0 or missing', () => {
    expect(computeInventoryCoverage(1000, { unitsPerDay: 0 }).coverageDays).toBeNull()
    expect(computeInventoryCoverage(1000, undefined).coverageDays).toBeNull()
  })

  it('returns null for a negative quantity (invalid, not silently computed)', () => {
    const result = computeInventoryCoverage(-5, { unitsPerDay: 500 })
    expect(result.coverageDays).toBeNull()
    expect(result.explain.exclusions.some((e) => e.includes('negativ'))).toBe(true)
  })

  it('falls back to shifts-only coverage when the shift model is invalid ONLY because hours/breaks are bad (shiftsPerDay itself is fine)', () => {
    // hoursPerShift 0 makes the shift model invalid, but shiftsPerDay=2 is independently valid.
    const result = computeInventoryCoverage(1000, { unitsPerDay: 500 }, { hoursPerShift: 0, shiftsPerDay: 2, breakMinPerShift: 0 })
    expect(result.coverageDays).toBe(2)
    expect(result.coverageShifts).toBe(4) // 2 days * 2 shifts/day
    expect(result.coverageHours).toBeNull()
    expect(result.coverageMin).toBeNull()
  })

  it('does NOT fall back to a bogus shifts figure when shiftsPerDay itself is the invalid part', () => {
    const result = computeInventoryCoverage(1000, { unitsPerDay: 500 }, { hoursPerShift: 8, shiftsPerDay: 0, breakMinPerShift: 0 })
    expect(result.coverageDays).toBe(2)
    expect(result.coverageShifts).toBeNull()
  })

  it('carries a formula/dataBasis/exclusions explain object', () => {
    const explain = computeInventoryCoverage(undefined, undefined).explain
    expect(explain.formula.length).toBeGreaterThan(0)
    expect(explain.dataBasis.length).toBeGreaterThan(0)
    expect(explain.exclusions.length).toBeGreaterThan(0)
  })
})
