/**
 * Unified Error Handling for Customer Portal
 *
 * Single source of truth for error codes and user-friendly messages.
 * Used by both BFF (for generating responses) and Portal (for parsing responses).
 */

import { z } from "zod";

// ============================================================================
// Error Categories and Severity
// ============================================================================

export type ErrorCategory =
  | "authentication"
  | "authorization"
  | "validation"
  | "business"
  | "system"
  | "network";

export type ErrorSeverity = "low" | "medium" | "high" | "critical";

// ============================================================================
// Error Code Registry
// ============================================================================

/**
 * All error codes used in the application.
 * Format: CATEGORY_NUMBER (e.g., AUTH_001, VAL_001)
 */
export const ErrorCode = {
  // Authentication Errors (AUTH_*)
  INVALID_CREDENTIALS: "AUTH_001",
  ACCOUNT_LOCKED: "AUTH_002",
  SESSION_EXPIRED: "AUTH_003",
  TOKEN_INVALID: "AUTH_004",
  TOKEN_REVOKED: "AUTH_005",
  REFRESH_TOKEN_INVALID: "AUTH_006",

  // Authorization Errors (AUTHZ_*)
  FORBIDDEN: "AUTHZ_001",
  ADMIN_REQUIRED: "AUTHZ_002",
  RESOURCE_ACCESS_DENIED: "AUTHZ_003",

  // Validation Errors (VAL_*)
  VALIDATION_FAILED: "VAL_001",
  REQUIRED_FIELD_MISSING: "VAL_002",
  INVALID_FORMAT: "VAL_003",
  NOT_FOUND: "VAL_004",

  // Business Logic Errors (BIZ_*)
  ACCOUNT_EXISTS: "BIZ_001",
  ACCOUNT_ALREADY_LINKED: "BIZ_002",
  CUSTOMER_NOT_FOUND: "BIZ_003",
  ORDER_ALREADY_PROCESSED: "BIZ_004",
  INSUFFICIENT_BALANCE: "BIZ_005",
  SERVICE_UNAVAILABLE: "BIZ_006",
  LEGACY_ACCOUNT_EXISTS: "BIZ_007",
  ACCOUNT_MAPPING_MISSING: "BIZ_008",

  // System Errors (SYS_*)
  INTERNAL_ERROR: "SYS_001",
  EXTERNAL_SERVICE_ERROR: "SYS_002",
  DATABASE_ERROR: "SYS_003",
  CONFIGURATION_ERROR: "SYS_004",

  // Network/Rate Limiting (NET_*)
  NETWORK_ERROR: "NET_001",
  TIMEOUT: "NET_002",
  RATE_LIMITED: "NET_003",

  // SIM Errors (SIM_*)
  SIM_ACTIVATION_FEE_REQUIRED: "SIM_001",
  SIM_NOT_FOUND: "SIM_002",
  SIM_PLAN_CHANGE_FAILED: "SIM_003",
  SIM_TOPUP_FAILED: "SIM_004",
  SIM_ACTIVATION_FAILED: "SIM_005",
  SIM_CANCELLATION_FAILED: "SIM_006",

  // Internet Errors (INT_*)
  INTERNET_ELIGIBILITY_NOT_REQUESTED: "INT_001",
  INTERNET_ELIGIBILITY_PENDING: "INT_002",
  INTERNET_INELIGIBLE: "INT_003",
  INTERNET_SERVICE_EXISTS: "INT_004",
  INTERNET_CHECK_FAILED: "INT_005",

  // Order Validation Errors (ORD_*)
  USER_MAPPING_NOT_FOUND: "ORD_001",
  WHMCS_CLIENT_NOT_LINKED: "ORD_002",
  NO_PAYMENT_METHOD: "ORD_003",
  INVALID_SKU: "ORD_004",
  RESIDENCE_CARD_NOT_SUBMITTED: "ORD_005",
  RESIDENCE_CARD_REJECTED: "ORD_006",
  ORDER_VALIDATION_FAILED: "ORD_007",
  FULFILLMENT_FAILED: "ORD_008",

  // Subscription Errors (SUB_*)
  SUBSCRIPTION_NOT_FOUND: "SUB_001",
  SUBSCRIPTION_CANCELLATION_FAILED: "SUB_002",
  SUBSCRIPTION_UPDATE_FAILED: "SUB_003",

  // Generic
  UNKNOWN: "GEN_001",
} as const;

export type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];

// ============================================================================
// Error Messages (User-Friendly)
// ============================================================================

/**
 * User-friendly error messages for each error code.
 * These are safe to display to end users.
 */
export const ErrorMessages: Record<ErrorCodeType, string> = {
  // Authentication
  [ErrorCode.INVALID_CREDENTIALS]: "Invalid email or password. Please try again.",
  [ErrorCode.ACCOUNT_LOCKED]:
    "Your account has been temporarily locked due to multiple failed login attempts. Please try again later.",
  [ErrorCode.SESSION_EXPIRED]: "Your session has expired. Please log in again.",
  [ErrorCode.TOKEN_INVALID]: "Your session is invalid. Please log in again.",
  [ErrorCode.TOKEN_REVOKED]: "Your session has been revoked. Please log in again.",
  [ErrorCode.REFRESH_TOKEN_INVALID]: "Your session could not be refreshed. Please log in again.",

  // Authorization
  [ErrorCode.FORBIDDEN]: "You do not have permission to perform this action.",
  [ErrorCode.ADMIN_REQUIRED]: "Administrator access is required for this action.",
  [ErrorCode.RESOURCE_ACCESS_DENIED]: "You do not have access to this resource.",

  // Validation
  [ErrorCode.VALIDATION_FAILED]: "The provided data is invalid. Please check your input.",
  [ErrorCode.REQUIRED_FIELD_MISSING]: "Required information is missing.",
  [ErrorCode.INVALID_FORMAT]: "The data format is invalid.",
  [ErrorCode.NOT_FOUND]: "The requested resource was not found.",

  // Business Logic
  [ErrorCode.ACCOUNT_EXISTS]:
    "We couldn't create a new account with these details. Please sign in or contact support.",
  [ErrorCode.ACCOUNT_ALREADY_LINKED]:
    "This billing account is already linked to a portal account. Please sign in.",
  [ErrorCode.LEGACY_ACCOUNT_EXISTS]:
    "We couldn't create a new account with these details. Please transfer your account or contact support.",
  [ErrorCode.CUSTOMER_NOT_FOUND]: "Customer account not found. Please contact support.",
  [ErrorCode.ORDER_ALREADY_PROCESSED]: "This order has already been processed.",
  [ErrorCode.INSUFFICIENT_BALANCE]: "Insufficient account balance.",
  [ErrorCode.SERVICE_UNAVAILABLE]:
    "This service is temporarily unavailable. Please try again later.",
  [ErrorCode.ACCOUNT_MAPPING_MISSING]:
    "Your account isn’t fully set up yet. Please contact support or try again later.",

  // System
  [ErrorCode.INTERNAL_ERROR]: "An unexpected error occurred. Please try again later.",
  [ErrorCode.EXTERNAL_SERVICE_ERROR]:
    "An external service is temporarily unavailable. Please try again later.",
  [ErrorCode.DATABASE_ERROR]: "A system error occurred. Please try again later.",
  [ErrorCode.CONFIGURATION_ERROR]: "A system configuration error occurred. Please contact support.",

  // Network
  [ErrorCode.NETWORK_ERROR]:
    "Unable to connect to the server. Please check your internet connection.",
  [ErrorCode.TIMEOUT]: "The request timed out. Please try again.",
  [ErrorCode.RATE_LIMITED]: "Too many requests. Please wait a moment and try again.",

  // SIM
  [ErrorCode.SIM_ACTIVATION_FEE_REQUIRED]: "SIM orders require an activation fee.",
  [ErrorCode.SIM_NOT_FOUND]: "SIM subscription not found.",
  [ErrorCode.SIM_PLAN_CHANGE_FAILED]: "Failed to change SIM plan. Please try again.",
  [ErrorCode.SIM_TOPUP_FAILED]: "Failed to top up SIM data. Please try again.",
  [ErrorCode.SIM_ACTIVATION_FAILED]: "SIM activation failed. Please contact support.",
  [ErrorCode.SIM_CANCELLATION_FAILED]: "SIM cancellation failed. Please try again.",

  // Internet
  [ErrorCode.INTERNET_ELIGIBILITY_NOT_REQUESTED]:
    "Internet eligibility review is required before ordering.",
  [ErrorCode.INTERNET_ELIGIBILITY_PENDING]:
    "Internet eligibility review is still in progress. Please wait for review to complete.",
  [ErrorCode.INTERNET_INELIGIBLE]:
    "Internet service is not available for your address. Please contact support.",
  [ErrorCode.INTERNET_SERVICE_EXISTS]:
    "An active Internet service already exists for this account.",
  [ErrorCode.INTERNET_CHECK_FAILED]: "Unable to verify Internet eligibility. Please try again.",

  // Order Validation
  [ErrorCode.USER_MAPPING_NOT_FOUND]: "User account mapping is required before ordering.",
  [ErrorCode.WHMCS_CLIENT_NOT_LINKED]: "Billing system integration is required before ordering.",
  [ErrorCode.NO_PAYMENT_METHOD]: "A payment method is required before ordering.",
  [ErrorCode.INVALID_SKU]: "One or more products in your order are invalid.",
  [ErrorCode.RESIDENCE_CARD_NOT_SUBMITTED]: "Residence card submission is required for SIM orders.",
  [ErrorCode.RESIDENCE_CARD_REJECTED]:
    "Your residence card was rejected. Please resubmit and try again.",
  [ErrorCode.ORDER_VALIDATION_FAILED]: "Order validation failed. Please check your order details.",
  [ErrorCode.FULFILLMENT_FAILED]: "Order fulfillment failed. Please contact support.",

  // Subscription
  [ErrorCode.SUBSCRIPTION_NOT_FOUND]: "Subscription not found.",
  [ErrorCode.SUBSCRIPTION_CANCELLATION_FAILED]:
    "Subscription cancellation failed. Please try again.",
  [ErrorCode.SUBSCRIPTION_UPDATE_FAILED]: "Subscription update failed. Please try again.",

  // Generic
  [ErrorCode.UNKNOWN]: "An unexpected error occurred. Please try again.",
};

// ============================================================================
// Error Metadata
// ============================================================================

interface ErrorMetadata {
  category: ErrorCategory;
  severity: ErrorSeverity;
  shouldLogout: boolean;
  shouldRetry: boolean;
  logLevel: "error" | "warn" | "info" | "debug";
}

/**
 * Metadata for each error code defining behavior and classification.
 */
export const ErrorMetadata: Record<ErrorCodeType, ErrorMetadata> = {
  // Authentication - mostly medium severity, some trigger logout
  [ErrorCode.INVALID_CREDENTIALS]: {
    category: "authentication",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "warn",
  },
  [ErrorCode.ACCOUNT_LOCKED]: {
    category: "authentication",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "warn",
  },
  [ErrorCode.SESSION_EXPIRED]: {
    category: "authentication",
    severity: "low",
    shouldLogout: true,
    shouldRetry: false,
    // Session expiry is an expected flow (browser tabs, refresh loops, etc.) and can be extremely noisy.
    // Keep it available for debugging but avoid spamming production logs at info level.
    logLevel: "debug",
  },
  [ErrorCode.TOKEN_INVALID]: {
    category: "authentication",
    severity: "medium",
    shouldLogout: true,
    shouldRetry: false,
    logLevel: "warn",
  },
  [ErrorCode.TOKEN_REVOKED]: {
    category: "authentication",
    severity: "medium",
    shouldLogout: true,
    shouldRetry: false,
    logLevel: "warn",
  },
  [ErrorCode.REFRESH_TOKEN_INVALID]: {
    category: "authentication",
    severity: "medium",
    shouldLogout: true,
    shouldRetry: false,
    logLevel: "warn",
  },

  // Authorization
  [ErrorCode.FORBIDDEN]: {
    category: "authorization",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "warn",
  },
  [ErrorCode.ADMIN_REQUIRED]: {
    category: "authorization",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "warn",
  },
  [ErrorCode.RESOURCE_ACCESS_DENIED]: {
    category: "authorization",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "warn",
  },

  // Validation - low severity, informational
  [ErrorCode.VALIDATION_FAILED]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "info",
  },
  [ErrorCode.REQUIRED_FIELD_MISSING]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "info",
  },
  [ErrorCode.INVALID_FORMAT]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "info",
  },
  [ErrorCode.NOT_FOUND]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "info",
  },

  // Business Logic
  [ErrorCode.ACCOUNT_EXISTS]: {
    category: "business",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "info",
  },
  [ErrorCode.ACCOUNT_ALREADY_LINKED]: {
    category: "business",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "info",
  },
  [ErrorCode.LEGACY_ACCOUNT_EXISTS]: {
    category: "business",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "info",
  },
  [ErrorCode.CUSTOMER_NOT_FOUND]: {
    category: "business",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "warn",
  },
  [ErrorCode.ORDER_ALREADY_PROCESSED]: {
    category: "business",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "info",
  },
  [ErrorCode.INSUFFICIENT_BALANCE]: {
    category: "business",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "info",
  },
  [ErrorCode.SERVICE_UNAVAILABLE]: {
    category: "business",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "warn",
  },
  [ErrorCode.ACCOUNT_MAPPING_MISSING]: {
    category: "business",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "warn",
  },

  // System - high severity
  [ErrorCode.INTERNAL_ERROR]: {
    category: "system",
    severity: "high",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "error",
  },
  [ErrorCode.EXTERNAL_SERVICE_ERROR]: {
    category: "system",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "error",
  },
  [ErrorCode.DATABASE_ERROR]: {
    category: "system",
    severity: "critical",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "error",
  },
  [ErrorCode.CONFIGURATION_ERROR]: {
    category: "system",
    severity: "critical",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "error",
  },

  // Network
  [ErrorCode.NETWORK_ERROR]: {
    category: "network",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "warn",
  },
  [ErrorCode.TIMEOUT]: {
    category: "network",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "warn",
  },
  [ErrorCode.RATE_LIMITED]: {
    category: "network",
    severity: "low",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "warn",
  },

  // SIM Errors
  [ErrorCode.SIM_ACTIVATION_FEE_REQUIRED]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "info",
  },
  [ErrorCode.SIM_NOT_FOUND]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "warn",
  },
  [ErrorCode.SIM_PLAN_CHANGE_FAILED]: {
    category: "business",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "error",
  },
  [ErrorCode.SIM_TOPUP_FAILED]: {
    category: "business",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "error",
  },
  [ErrorCode.SIM_ACTIVATION_FAILED]: {
    category: "business",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "error",
  },
  [ErrorCode.SIM_CANCELLATION_FAILED]: {
    category: "business",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "error",
  },

  // Internet Errors
  [ErrorCode.INTERNET_ELIGIBILITY_NOT_REQUESTED]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "info",
  },
  [ErrorCode.INTERNET_ELIGIBILITY_PENDING]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "info",
  },
  [ErrorCode.INTERNET_INELIGIBLE]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "info",
  },
  [ErrorCode.INTERNET_SERVICE_EXISTS]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "warn",
  },
  [ErrorCode.INTERNET_CHECK_FAILED]: {
    category: "system",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "error",
  },

  // Order Validation Errors
  [ErrorCode.USER_MAPPING_NOT_FOUND]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "warn",
  },
  [ErrorCode.WHMCS_CLIENT_NOT_LINKED]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "warn",
  },
  [ErrorCode.NO_PAYMENT_METHOD]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "info",
  },
  [ErrorCode.INVALID_SKU]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "warn",
  },
  [ErrorCode.RESIDENCE_CARD_NOT_SUBMITTED]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "info",
  },
  [ErrorCode.RESIDENCE_CARD_REJECTED]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "warn",
  },
  [ErrorCode.ORDER_VALIDATION_FAILED]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "warn",
  },
  [ErrorCode.FULFILLMENT_FAILED]: {
    category: "system",
    severity: "high",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "error",
  },

  // Subscription Errors
  [ErrorCode.SUBSCRIPTION_NOT_FOUND]: {
    category: "validation",
    severity: "low",
    shouldLogout: false,
    shouldRetry: false,
    logLevel: "warn",
  },
  [ErrorCode.SUBSCRIPTION_CANCELLATION_FAILED]: {
    category: "business",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "error",
  },
  [ErrorCode.SUBSCRIPTION_UPDATE_FAILED]: {
    category: "business",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "error",
  },

  // Generic
  [ErrorCode.UNKNOWN]: {
    category: "system",
    severity: "medium",
    shouldLogout: false,
    shouldRetry: true,
    logLevel: "error",
  },
};

// ============================================================================
// Helper Functions
// ============================================================================

/**
 * Map HTTP status codes to domain error codes.
 * Shared between BFF (for responses) and Portal (for parsing).
 */
export function mapHttpStatusToErrorCode(status?: number): ErrorCodeType {
  if (!status) return ErrorCode.UNKNOWN;

  switch (status) {
    case 401:
      return ErrorCode.SESSION_EXPIRED;
    case 403:
      return ErrorCode.FORBIDDEN;
    case 404:
      return ErrorCode.NOT_FOUND;
    case 409:
      return ErrorCode.ACCOUNT_EXISTS;
    case 400:
      return ErrorCode.VALIDATION_FAILED;
    case 429:
      return ErrorCode.RATE_LIMITED;
    case 503:
      return ErrorCode.SERVICE_UNAVAILABLE;
    default:
      return status >= 500 ? ErrorCode.INTERNAL_ERROR : ErrorCode.UNKNOWN;
  }
}

/**
 * Get user-friendly message for an error code
 */
export function getMessageForErrorCode(code: string): string {
  return ErrorMessages[code as ErrorCodeType] ?? ErrorMessages[ErrorCode.UNKNOWN];
}

/**
 * Get metadata for an error code
 */
export function getErrorMetadata(code: string): ErrorMetadata {
  return ErrorMetadata[code as ErrorCodeType] ?? ErrorMetadata[ErrorCode.UNKNOWN];
}

/**
 * Check if error code should trigger logout
 */
export function shouldLogoutForCode(code: string): boolean {
  return getErrorMetadata(code).shouldLogout;
}

/**
 * Check if error can be retried
 */
export function canRetryError(code: string): boolean {
  return getErrorMetadata(code).shouldRetry;
}

// NOTE: We intentionally do NOT support matching error messages to codes.
// Error codes must be explicit and stable (returned from the API or thrown by server code).

// ============================================================================
// Zod Schema for Error Response
// ============================================================================

/**
 * Schema for standard API error response
 */
export const apiErrorSchema = z.object({
  success: z.literal(false),
  error: z.object({
    code: z.string(),
    message: z.string(),
    details: z.record(z.string(), z.unknown()).optional(),
  }),
});

export type ApiError = z.infer<typeof apiErrorSchema>;

/**
 * Create a standard error response object
 */
export function createErrorResponse(
  code: ErrorCodeType,
  customMessage?: string,
  details?: Record<string, unknown>
): ApiError {
  return {
    success: false,
    error: {
      code,
      message: customMessage ?? getMessageForErrorCode(code),
      details,
    },
  };
}
