import type { VatRate } from './resolve.js'

const TEN_THOUSAND = 10_000n

/** A money amount failed the non-negative-agorot trust-boundary contract. */
export class InvalidAmountError extends Error {
  readonly amount: string

  constructor(label: string, amount: bigint) {
    super(`${label} must be a non-negative integer agorot amount, got ${amount}`)
    this.name = 'InvalidAmountError'
    this.amount = String(amount)
  }
}

/**
 * Round-half-up via `floor((2a + b) / (2b))` — exact for any positive denominator.
 * Correct only for a NON-NEGATIVE numerator: BigInt `/` truncates toward zero, so
 * a negative numerator would diverge from `floor` (off-by-one wrong money). Callers
 * guard amount ≥ 0 and the rate brand guarantees bp ≥ 0, so `a ≥ 0` always holds.
 */
function roundHalfUp(numerator: bigint, denominator: bigint): bigint {
  return (2n * numerator + denominator) / (2n * denominator)
}

/** Exclusive: VAT added to net; `gross = net + vat`. */
export function applyVat(
  netAgorot: bigint,
  rate: VatRate,
): { vat: bigint; gross: bigint } {
  if (netAgorot < 0n) throw new InvalidAmountError('netAgorot', netAgorot)
  const vat = roundHalfUp(netAgorot * rate, TEN_THOUSAND)
  return { vat, gross: netAgorot + vat }
}

/** Inclusive: VAT extracted from gross; `net = gross − vat`. */
export function extractVat(
  grossAgorot: bigint,
  rate: VatRate,
): { net: bigint; vat: bigint } {
  if (grossAgorot < 0n) throw new InvalidAmountError('grossAgorot', grossAgorot)
  const denominator = TEN_THOUSAND + rate
  const vat = roundHalfUp(grossAgorot * rate, denominator)
  return { net: grossAgorot - vat, vat }
}
