import { PromoValidationError } from './errors.js'

export type PromoKind = 'percentage' | 'fixed' | 'bogo'
export type PromoFunder = 'platform' | 'vendor'
export type PromoScope =
  | { kind: 'all' }
  | { kind: 'products'; ids: string[] }
  | { kind: 'categories'; ids: string[] }
  | { kind: 'tags'; tags: string[] }
  | { kind: 'vendor'; vendorId: string }

export interface PromoEligibility {
  firstPurchaseOnly?: boolean
  membersOnly?: boolean
  allowlistOnly?: boolean
}

export interface Promo {
  id: string
  code: string
  kind: PromoKind
  valueBps?: number
  valueAmount?: bigint
  currency?: string
  /** Percentage promos only: maximum discount granted, in minor units. */
  maxDiscountAmount?: bigint
  bogo?: { buyQty: number; getQty: number }
  scope: PromoScope
  eligibility: PromoEligibility
  funder: PromoFunder
  maxUses?: number
  perUserCap?: number
  startsAt?: Date
  endsAt?: Date
  minOrderAmount?: bigint
  /** Maximum eligible cart subtotal, in minor units; twin of minOrderAmount. */
  maxOrderAmount?: bigint
  active: boolean
  vendorId: string | null
}

export interface PromoContext {
  now: Date
  userId: string | null
  cartSubtotal: bigint
  cartCurrency: string
  lines: DiscountLine[]
  isFirstPurchase?: boolean
  isMember?: boolean
  isAllowlisted?: boolean
  globalUses?: number
  userRedemptionCount?: number
}

export interface DiscountLine {
  lineId: string
  unitPrice: bigint
  qty: number
  vendorId: string | null
  productId?: string
  categoryIds?: string[]
  tags?: string[]
}

export interface DiscountableCart {
  currency: string
  lines: DiscountLine[]
}

export type PromoRejectReason =
  | 'inactive'
  | 'not_started'
  | 'expired'
  | 'min_order_not_met'
  | 'max_order_exceeded'
  | 'currency_mismatch'
  | 'out_of_scope'
  | 'not_first_purchase'
  | 'not_member'
  | 'not_on_allowlist'
  | 'quota_exhausted'
  | 'per_user_cap_reached'

export type PromoValidation = { ok: true; promo: Promo } | { ok: false; reason: PromoRejectReason }

export interface DiscountResult {
  total: bigint
  perLine: Array<{ lineId: string; amount: bigint }>
  funder: PromoFunder
}

export const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i

export function assertUuid(value: string, field: string): void {
  if (!UUID_RE.test(value)) {
    throw new PromoValidationError(field)
  }
}

export function assertPositiveInt(n: number, field: string): void {
  if (!Number.isInteger(n) || n <= 0) {
    throw new PromoValidationError(field)
  }
}
