export const CONVERSION_STATUSES = [
  'Queued',
  'Processing',
  'Complete',
  'Failed',
] as const
export type ConversionStatus = (typeof CONVERSION_STATUSES)[number]

const CONVERSION_TRANSITIONS = {
  Queued: ['Processing', 'Failed'],
  Processing: ['Complete', 'Failed'],
  Complete: [],
  Failed: [],
} as const satisfies Record<ConversionStatus, readonly ConversionStatus[]>

export function isConversionStatus(value: unknown): value is ConversionStatus {
  return typeof value === 'string' && (CONVERSION_STATUSES as readonly string[]).includes(value)
}

export function canTransitionConversion(
  from: ConversionStatus,
  to: ConversionStatus,
): boolean {
  return (CONVERSION_TRANSITIONS[from] as readonly ConversionStatus[]).includes(to)
}

export function assertConversionTransition(
  from: ConversionStatus,
  to: ConversionStatus,
): void {
  if (!canTransitionConversion(from, to)) {
    throw new Error(`Invalid conversion transition: ${from} -> ${to}`)
  }
}

export const PAYMENT_STATES = [
  'pending',
  'paid',
  'failed',
  'cancelled',
  'refunded',
  'disputed',
  'chargeback',
  'reconciliation',
] as const
export type PaymentState = (typeof PAYMENT_STATES)[number]

const PAYMENT_TRANSITIONS = {
  pending: ['paid', 'failed', 'cancelled', 'reconciliation'],
  paid: ['refunded', 'disputed', 'chargeback', 'reconciliation'],
  failed: [],
  cancelled: [],
  refunded: [],
  disputed: ['paid', 'refunded', 'chargeback', 'reconciliation'],
  chargeback: [],
  reconciliation: ['paid', 'refunded', 'disputed', 'chargeback'],
} as const satisfies Record<PaymentState, readonly PaymentState[]>

export function isPaymentState(value: unknown): value is PaymentState {
  return typeof value === 'string' && (PAYMENT_STATES as readonly string[]).includes(value)
}

export function canTransitionPayment(from: PaymentState, to: PaymentState): boolean {
  return (PAYMENT_TRANSITIONS[from] as readonly PaymentState[]).includes(to)
}

export const REVERSAL_STATES = ['none', 'pending', 'applied'] as const
export type ReversalState = (typeof REVERSAL_STATES)[number]

export type CreditReversal = Readonly<{
  originalGrantId: string
  reversalEntryId: string
  amount: bigint
  state: Exclude<ReversalState, 'none'>
}>

export function createAppliedReversal(input: {
  originalGrantId: string
  reversalEntryId: string
  amount: bigint
}): CreditReversal {
  if (input.amount <= 0n) throw new RangeError('Reversal amount must be positive')
  if (!input.originalGrantId || !input.reversalEntryId) {
    throw new TypeError('A reversal must link both ledger entries')
  }
  return { ...input, state: 'applied' }
}
