import {
  OrderChargeConflictError,
  OrderIdempotencyConflictError,
  OrderNotFoundError,
  isOrderChargeConflictError,
  isOrderIdempotencyConflictError,
  isOrderNotFoundError,
} from '@platform-modules/commerce-orders'
import type { StaleSplit } from './types.js'

export type CheckoutValidationReason =
  | 'EMPTY_CART'
  | 'STALE_ITEMS'
  | 'CURRENCY_MISMATCH'
  | 'INVALID_CHARGE_KEY'
  | 'UNKNOWN_COUNTRY'
  | 'INVALID_QTY'

function httpStatusForCheckoutValidation(
  reason: CheckoutValidationReason,
): 400 | 409 | 422 {
  switch (reason) {
    case 'EMPTY_CART':
    case 'INVALID_CHARGE_KEY':
    case 'INVALID_QTY':
      return 400
    case 'STALE_ITEMS':
      return 409
    case 'CURRENCY_MISMATCH':
    case 'UNKNOWN_COUNTRY':
      return 422
  }
}

export class CheckoutValidationError extends Error {
  override readonly name = 'CheckoutValidationError'
  readonly code = 'CHECKOUT_VALIDATION' as const
  readonly httpStatus: 400 | 409 | 422

  constructor(
    readonly reason: CheckoutValidationReason,
    readonly stale?: StaleSplit,
  ) {
    super(`checkout validation failed: ${reason}`)
    this.httpStatus = httpStatusForCheckoutValidation(reason)
  }
}

export class OrderNotChargeableError extends Error {
  override readonly name = 'OrderNotChargeableError'
  readonly code = 'ORDER_NOT_CHARGEABLE' as const
  readonly httpStatus = 409 as const

  constructor(readonly orderId: string) {
    super(`order not chargeable: ${orderId}`)
  }
}

export class PaymentFailedError extends Error {
  override readonly name = 'PaymentFailedError'
  readonly code = 'PAYMENT_FAILED' as const
  readonly httpStatus = 402 as const

  constructor(readonly cause: unknown) {
    super('payment failed')
  }
}

export class FulfillmentIncompleteError extends Error {
  override readonly name = 'FulfillmentIncompleteError'
  readonly code = 'FULFILLMENT_INCOMPLETE' as const
  readonly httpStatus = 500 as const

  constructor(
    readonly context: {
      orderId: string
      overall: 'partial' | 'unfulfillable'
      failures: { lineId: string; error: string }[]
    },
  ) {
    super(`fulfillment incomplete for order ${context.orderId}: ${context.overall}`)
  }
}

export {
  OrderChargeConflictError,
  OrderIdempotencyConflictError,
  OrderNotFoundError,
  isOrderChargeConflictError,
  isOrderIdempotencyConflictError,
  isOrderNotFoundError,
}

export function isCheckoutValidationError(e: unknown): e is CheckoutValidationError {
  return (
    typeof e === 'object' &&
    e !== null &&
    (e as { name?: unknown }).name === 'CheckoutValidationError' &&
    (e as { code?: unknown }).code === 'CHECKOUT_VALIDATION'
  )
}

export function isOrderNotChargeableError(e: unknown): e is OrderNotChargeableError {
  return (
    typeof e === 'object' &&
    e !== null &&
    (e as { name?: unknown }).name === 'OrderNotChargeableError' &&
    (e as { code?: unknown }).code === 'ORDER_NOT_CHARGEABLE'
  )
}

export function isPaymentFailedError(e: unknown): e is PaymentFailedError {
  return (
    typeof e === 'object' &&
    e !== null &&
    (e as { name?: unknown }).name === 'PaymentFailedError' &&
    (e as { code?: unknown }).code === 'PAYMENT_FAILED'
  )
}

export function isFulfillmentIncompleteError(e: unknown): e is FulfillmentIncompleteError {
  return (
    typeof e === 'object' &&
    e !== null &&
    (e as { name?: unknown }).name === 'FulfillmentIncompleteError' &&
    (e as { code?: unknown }).code === 'FULFILLMENT_INCOMPLETE'
  )
}
