import type { Cart, CartLine, PriceSnapshot } from '@platform-modules/commerce-cart'
import type { ProductKind } from '@platform-modules/commerce-orders'
import { IL_VAT_SCHEDULE, resolveVatRate } from '@platform-modules/tax/rates-table'
import { describe, expect, it } from 'vitest'
import type { CatalogSnapshot } from './types.js'
import { validateCheckout } from './validate.js'

const VAT_RATE = resolveVatRate(IL_VAT_SCHEDULE, '2026-06-20')

function price(amount: bigint, currency = 'ILS', priceMode: PriceSnapshot['priceMode'] = 'exclusive'): PriceSnapshot {
  return { amount, currency, priceMode }
}

function line(
  variantId: string,
  qty: number,
  amount: bigint,
  priceMode: PriceSnapshot['priceMode'] = 'exclusive',
): CartLine {
  return {
    lineId: `line-${variantId}`,
    variantId,
    qty,
    price: price(amount, 'ILS', priceMode),
    vendorId: null,
  }
}

function cart(lines: CartLine[], currency = 'ILS'): Cart {
  const subtotal = lines.reduce((sum, l) => sum + l.price.amount * BigInt(l.qty), 0n)
  return { id: 'cart-1', currency, lines, subtotal }
}

function catalogFrom(
  entries: Record<string, { available: boolean; price: PriceSnapshot; title?: string; kind?: ProductKind }>,
): CatalogSnapshot {
  return new Map(
    Object.entries(entries).map(([variantId, entry]) => [
      variantId,
      { kind: entry.kind ?? 'digital', ...entry },
    ]),
  )
}

const baseInput = {
  currency: 'ILS',
  priceMode: 'exclusive' as const,
  vatRate: VAT_RATE,
}

describe('validate-empty-cart', () => {
  it('0 lines → EMPTY_CART', () => {
    const result = validateCheckout({
      ...baseInput,
      cart: cart([]),
      catalog: catalogFrom({}),
    })
    expect(result).toEqual({ ok: false, error: 'EMPTY_CART' })
  })
})

describe('validate-stale-removed', () => {
  it('removed item → STALE_ITEMS with exact stale split', () => {
    const variantId = 'variant-missing'
    const result = validateCheckout({
      ...baseInput,
      cart: cart([line(variantId, 1, 1000n)]),
      catalog: catalogFrom({}),
    })
    expect(result).toEqual({
      ok: false,
      error: 'STALE_ITEMS',
      stale: { removed: [variantId], updated: [] },
    })
  })

  it('unavailable catalog entry → removed', () => {
    const variantId = 'variant-unavail'
    const result = validateCheckout({
      ...baseInput,
      cart: cart([line(variantId, 1, 1000n)]),
      catalog: catalogFrom({
        [variantId]: { available: false, price: price(1000n) },
      }),
    })
    expect(result).toEqual({
      ok: false,
      error: 'STALE_ITEMS',
      stale: { removed: [variantId], updated: [] },
    })
  })
})

describe('validate-stale-priced', () => {
  it('drifted price → STALE_ITEMS with exact stale split', () => {
    const variantId = 'variant-drift'
    const result = validateCheckout({
      ...baseInput,
      cart: cart([line(variantId, 1, 1000n)]),
      catalog: catalogFrom({
        [variantId]: { available: true, price: price(1200n) },
      }),
    })
    expect(result).toEqual({
      ok: false,
      error: 'STALE_ITEMS',
      stale: {
        removed: [],
        updated: [{ variantId, was: 1000n, now: 1200n }],
      },
    })
  })
})

describe('validate-currency-mismatch', () => {
  it('line currency ≠ input → CURRENCY_MISMATCH', () => {
    const usdLine = line('v1', 1, 1000n)
    usdLine.price = price(1000n, 'USD')
    const result = validateCheckout({
      ...baseInput,
      cart: cart([usdLine]),
      catalog: catalogFrom({
        v1: { available: true, price: price(1000n, 'USD') },
      }),
    })
    expect(result).toEqual({ ok: false, error: 'CURRENCY_MISMATCH' })
  })

  it('input currency ≠ cart.currency → CURRENCY_MISMATCH', () => {
    const result = validateCheckout({
      ...baseInput,
      currency: 'USD',
      cart: cart([line('v1', 1, 1000n)], 'ILS'),
      catalog: catalogFrom({
        v1: { available: true, price: price(1000n) },
      }),
    })
    expect(result).toEqual({ ok: false, error: 'CURRENCY_MISMATCH' })
  })
})

describe('validate-prices-vat-exclusive', () => {
  it('priceMode exclusive uses applyVat; all bigint exact minor units', () => {
    const variantId = 'v-exclusive'
    const result = validateCheckout({
      ...baseInput,
      priceMode: 'exclusive',
      cart: cart([line(variantId, 2, 1000n, 'exclusive')]),
      catalog: catalogFrom({
        [variantId]: { available: true, price: price(1000n, 'ILS', 'exclusive') },
      }),
    })

    expect(result.ok).toBe(true)
    if (!result.ok) return

    expect(result.lines).toHaveLength(1)
    const priced = result.lines[0]!
    expect(priced.variantId).toBe(variantId)
    expect(priced.qty).toBe(2)
    expect(priced.unitNet).toBe(1000n)
    expect(priced.vat).toBe(180n)
    expect(priced.lineTotal).toBe(2360n)

    for (const value of [priced.unitNet, priced.vat, priced.lineTotal]) {
      expect(typeof value).toBe('bigint')
    }
  })
})

describe('validate-prices-vat-inclusive', () => {
  it('priceMode inclusive uses extractVat; all bigint exact minor units', () => {
    const variantId = 'v-inclusive'
    const result = validateCheckout({
      ...baseInput,
      priceMode: 'inclusive',
      cart: cart([line(variantId, 2, 1180n, 'inclusive')]),
      catalog: catalogFrom({
        [variantId]: { available: true, price: price(1180n, 'ILS', 'inclusive') },
      }),
    })

    expect(result.ok).toBe(true)
    if (!result.ok) return

    expect(result.lines).toHaveLength(1)
    const priced = result.lines[0]!
    expect(priced.unitNet).toBe(1000n)
    expect(priced.vat).toBe(180n)
    expect(priced.lineTotal).toBe(2360n)

    for (const value of [priced.unitNet, priced.vat, priced.lineTotal]) {
      expect(typeof value).toBe('bigint')
    }
  })
})

describe('validate-invalid-qty', () => {
  it('non-integer qty → INVALID_QTY', () => {
    const variantId = 'variant-fractional-qty'
    const cartLine = line(variantId, 1.5, 1000n)
    const result = validateCheckout({
      ...baseInput,
      cart: { id: 'cart-1', currency: 'ILS', lines: [cartLine], subtotal: 1500n },
      catalog: catalogFrom({
        [variantId]: { available: true, price: price(1000n) },
      }),
    })
    expect(result).toEqual({ ok: false, error: 'INVALID_QTY' })
  })

  it('zero qty → INVALID_QTY', () => {
    const variantId = 'variant-zero-qty'
    const result = validateCheckout({
      ...baseInput,
      cart: cart([line(variantId, 0, 1000n)]),
      catalog: catalogFrom({
        [variantId]: { available: true, price: price(1000n) },
      }),
    })
    expect(result).toEqual({ ok: false, error: 'INVALID_QTY' })
  })
})
