import type { Cart, PriceSnapshot } from '@platform-modules/commerce-cart'
import { applyVat, extractVat, type VatRate } from '@platform-modules/tax/rates-table'
import type { CatalogSnapshot, PricedLine, StaleSplit } from './types.js'

export type ValidateCheckoutInput = {
  cart: Cart
  catalog: CatalogSnapshot
  currency: string
  priceMode: 'inclusive' | 'exclusive'
  vatRate: VatRate
}

export type ValidateCheckoutResult =
  | { ok: true; lines: PricedLine[] }
  | {
      ok: false
      error: 'EMPTY_CART' | 'STALE_ITEMS' | 'CURRENCY_MISMATCH' | 'INVALID_QTY'
      stale?: StaleSplit
    }

function priceSnapshotsEqual(a: PriceSnapshot, b: PriceSnapshot): boolean {
  return (
    a.amount === b.amount &&
    a.currency === b.currency &&
    a.priceMode === b.priceMode
  )
}

export function validateCheckout(input: ValidateCheckoutInput): ValidateCheckoutResult {
  const { cart, catalog, currency, priceMode, vatRate } = input

  if (cart.lines.length === 0) {
    return { ok: false, error: 'EMPTY_CART' }
  }

  if (currency !== cart.currency) {
    return { ok: false, error: 'CURRENCY_MISMATCH' }
  }

  for (const line of cart.lines) {
    if (line.price.currency !== currency) {
      return { ok: false, error: 'CURRENCY_MISMATCH' }
    }
  }

  const stale: StaleSplit = { removed: [], updated: [] }

  for (const line of cart.lines) {
    const entry = catalog.get(line.variantId)
    if (entry === undefined || entry.available === false) {
      stale.removed.push(line.variantId)
      continue
    }

    if (!priceSnapshotsEqual(line.price, entry.price)) {
      stale.updated.push({
        variantId: line.variantId,
        was: line.price.amount,
        now: entry.price.amount,
      })
    }
  }

  if (stale.removed.length > 0 || stale.updated.length > 0) {
    return { ok: false, error: 'STALE_ITEMS', stale }
  }

  for (const line of cart.lines) {
    if (!Number.isInteger(line.qty) || line.qty <= 0) {
      return { ok: false, error: 'INVALID_QTY' }
    }
  }

  const lines: PricedLine[] = cart.lines.map((line) => {
    const qty = BigInt(line.qty)

    if (priceMode === 'exclusive') {
      const { vat, gross } = applyVat(line.price.amount, vatRate)
      return {
        variantId: line.variantId,
        qty: line.qty,
        unitNet: line.price.amount,
        vat,
        lineTotal: gross * qty,
      }
    }

    const { net, vat } = extractVat(line.price.amount, vatRate)
    return {
      variantId: line.variantId,
      qty: line.qty,
      unitNet: net,
      vat,
      lineTotal: line.price.amount * qty,
    }
  })

  return { ok: true, lines }
}
