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

export type {
  Actor,
  BuyerRef,
  Order,
  OrderLine,
  ProductKind,
} from '@platform-modules/commerce-orders'

export type FulfillmentKind = 'digital' | 'voucher' | 'physical'

export type VoucherState = 'UNREDEEMED' | 'REDEEMED' | 'EXPIRED' | 'CANCELLED'

export const VOUCHER_STATES: readonly VoucherState[] = [
  'UNREDEEMED',
  'REDEEMED',
  'EXPIRED',
  'CANCELLED',
] as const

export type ShipmentStatus =
  | 'pending'
  | 'labeled'
  | 'in_transit'
  | 'delivered'
  | 'failed'

export const SHIPMENT_STATUSES: readonly ShipmentStatus[] = [
  'pending',
  'labeled',
  'in_transit',
  'delivered',
  'failed',
] as const

export interface AccessGrant {
  id: string
  orderId: string
  itemId: string
  ownerKey: string
  blobKey: string
  createdAt: Date
}

export interface Voucher {
  id: string
  orderId: string
  lineId: string
  unitIndex: number
  vendorId: string | null
  state: VoucherState
  expiresAt: Date | null
  redeemedAt: Date | null
  createdAt: Date
}

export interface Address {
  name?: string
  line1: string
  line2?: string
  city: string
  region?: string
  postalCode: string
  country: string
  lat?: number
  lon?: number
}

export interface Shipment {
  id: string
  orderId: string
  lineIds: string[]
  address: Address
  status: ShipmentStatus
  carrierKind: string | null
  labelId: string | null
  trackingNumber: string | null
  createdAt: Date
  updatedAt: Date
}

export interface Label {
  id: string
  trackingNumber: string
  pdfKey?: string
  cost?: bigint
}

export interface CarrierTrackResult {
  trackingNumber: string
  status: ShipmentStatus
  events?: Array<{ timestamp: Date; description: string }>
}

export interface CarrierWebhookResult {
  eventId: string
  shipmentId?: string
  trackingNumber: string
  status: ShipmentStatus
}

export type FulfillmentOverall = 'fulfilled' | 'partial' | 'unfulfillable'

export type LineFulfillmentOutcome =
  | { lineId: string; kind: 'digital'; grantId: string }
  | { lineId: string; kind: 'voucher'; voucherIds: string[] }
  | { lineId: string; kind: 'physical'; shipmentId: string }
  | { lineId: string; kind: 'unfulfillable'; error: string }

export interface FulfillmentResult {
  orderId: string
  overall: FulfillmentOverall
  lines: LineFulfillmentOutcome[]
}

export type FulfillmentNotification =
  | { kind: 'digital-grant'; orderId: string; grantId: string; itemId: string }
  | { kind: 'voucher-issued'; orderId: string; lineId: string; codes: string[] }
  | { kind: 'shipment-labeled'; orderId: string; shipmentId: string; tracking: string }

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 FulfillmentValidationError(field)
  }
}

export function assertPositiveInt(qty: number, field = 'qty'): void {
  if (!Number.isInteger(qty) || qty <= 0) {
    throw new FulfillmentValidationError(field)
  }
}

export function normalizeEmail(email: string): string {
  return email.trim().toLowerCase()
}

export function ownerKeyOf(ref: { userId?: string; guestEmail?: string }): string {
  if (ref.userId) {
    return `user:${ref.userId}`
  }
  if (ref.guestEmail) {
    return `email:${normalizeEmail(ref.guestEmail)}`
  }
  throw new FulfillmentValidationError('owner')
}
