import { describe, expect, it } from 'vitest'
import { OrderIntegrityError, isOrderIntegrityError } from './errors.js'
import { assertOrderIntegrity } from './integrity.js'
import type { NewOrderLine, NewVendorSplit } from './types.js'

const line = (lineTotal: bigint): Pick<NewOrderLine, 'lineTotal'> => ({ lineTotal })
const split = (amount: bigint): Pick<NewVendorSplit, 'amount'> => ({ amount })

describe('assertOrderIntegrity', () => {
  it('rejects when line totals do not sum to subtotal', () => {
    expect(() =>
      assertOrderIntegrity({
        subtotal: 100n,
        tax: 0n,
        discount: 0n,
        total: 100n,
        lines: [line(60n), line(30n)],
        splits: [split(100n)],
      }),
    ).toThrow(OrderIntegrityError)

    try {
      assertOrderIntegrity({
        subtotal: 100n,
        tax: 0n,
        discount: 0n,
        total: 100n,
        lines: [line(60n), line(30n)],
        splits: [split(100n)],
      })
    } catch (e) {
      expect(isOrderIntegrityError(e)).toBe(true)
      expect((e as OrderIntegrityError).detail).toBe('lines')
    }
  })

  it('rejects when subtotal + tax - discount does not equal total', () => {
    expect(() =>
      assertOrderIntegrity({
        subtotal: 100n,
        tax: 10n,
        discount: 0n,
        total: 100n,
        lines: [line(100n)],
        splits: [split(100n)],
      }),
    ).toThrow(OrderIntegrityError)

    try {
      assertOrderIntegrity({
        subtotal: 100n,
        tax: 10n,
        discount: 0n,
        total: 100n,
        lines: [line(100n)],
        splits: [split(100n)],
      })
    } catch (e) {
      expect(isOrderIntegrityError(e)).toBe(true)
      expect((e as OrderIntegrityError).detail).toBe('total')
    }
  })

  it('rejects when vendor split amounts do not sum to total', () => {
    expect(() =>
      assertOrderIntegrity({
        subtotal: 100n,
        tax: 0n,
        discount: 0n,
        total: 100n,
        lines: [line(100n)],
        splits: [split(60n), split(30n)],
      }),
    ).toThrow(OrderIntegrityError)

    try {
      assertOrderIntegrity({
        subtotal: 100n,
        tax: 0n,
        discount: 0n,
        total: 100n,
        lines: [line(100n)],
        splits: [split(60n), split(30n)],
      })
    } catch (e) {
      expect(isOrderIntegrityError(e)).toBe(true)
      expect((e as OrderIntegrityError).detail).toBe('splits')
    }
  })
})
