import { describe, expect, it } from 'vitest'
import { blendReceipt, consumeAvg, type AvgValuation } from './weighted-average.js'

const EMPTY: AvgValuation = { quantity: 0, averageCost: 0 }

describe('weighted-average valuation', () => {
  it('blends an initial receipt into empty stock', () => {
    expect(blendReceipt(EMPTY, { quantity: 4, unitCost: 12.5 })).toEqual({
      quantity: 4,
      averageCost: 12.5,
    })
  })

  it('blends receipt into existing stock by weighted-average math', () => {
    expect(blendReceipt({ quantity: 4, averageCost: 10 }, { quantity: 2, unitCost: 16 })).toEqual({
      quantity: 6,
      averageCost: 12,
    })
  })

  it('does not change valuation when blending zero quantity', () => {
    expect(blendReceipt({ quantity: 7, averageCost: 5 }, { quantity: 0, unitCost: 20 })).toEqual({
      quantity: 7,
      averageCost: 5,
    })
  })

  it('consumes inventory at average cost and returns consumed value', () => {
    const result = consumeAvg({ quantity: 10, averageCost: 8 }, 3)
    expect(result).toMatchObject({
      quantity: 7,
      averageCost: 8,
      consumedQuantity: 3,
      consumedValue: 24,
    })
  })

  it('resets average cost to zero when fully consumed', () => {
    expect(consumeAvg({ quantity: 3, averageCost: 9 }, 3)).toMatchObject({
      quantity: 0,
      averageCost: 0,
      consumedQuantity: 3,
      consumedValue: 27,
    })
  })

  it('rejects over-consume', () => {
    expect(() => consumeAvg({ quantity: 2, averageCost: 7 }, 3)).toThrow(
      /cannot exceed available quantity/,
    )
  })

  it('validates blendReceipt args', () => {
    expect(() => blendReceipt({ quantity: -1, averageCost: 5 }, { quantity: 2, unitCost: 10 })).toThrow(
      /must be a non-negative integer/,
    )
    expect(() => blendReceipt({ quantity: 2, averageCost: 5 }, { quantity: 1.5, unitCost: 10 })).toThrow(
      /must be a non-negative integer/,
    )
    expect(() => blendReceipt({ quantity: 2, averageCost: 5 }, { quantity: 1, unitCost: -9 })).toThrow(
      /must be a finite non-negative number/,
    )
  })

  it('validates consumeAvg quantity', () => {
    expect(() => consumeAvg({ quantity: 2, averageCost: 5 }, -1)).toThrow(/must be a non-negative integer/)
  })
})
