import type { H3Error } from 'h3'
import { createError } from 'h3'
import type { ApiResponse } from '../../app/types/api'

/**
 * Standard API error class
 * Provides consistent error structure across the application
 */
export class ApiError extends Error {
  public statusCode: number
  public code?: string
  public details?: unknown

  constructor(
    statusCode: number,
    message: string,
    code?: string,
    details?: unknown
  ) {
    super(message)
    this.name = 'ApiError'
    this.statusCode = statusCode
    this.code = code
    this.details = details
  }

  /**
   * Convert to JSON format for API responses
   */
  toJSON(): ApiResponse<never> {
    return {
      success: false,
      error: this.message,
      code: this.code,
      statusCode: this.statusCode,
      ...(this.details ? { details: this.details } : {})
    }
  }
}

/**
 * Create a success API response
 * Use this in API routes to return standardized success responses
 *
 * @example
 * return createSuccessResponse(userData, 'User updated successfully')
 */
export function createSuccessResponse<T>(data: T, message?: string): ApiResponse<T> {
  return {
    success: true,
    data,
    ...(message && { message })
  }
}

/**
 * Create an API error with consistent structure
 *
 * @example
 * throw createApiError(400, 'Invalid input', 'INVALID_INPUT', { field: 'email' })
 */
export function createApiError(
  statusCode: number,
  message: string,
  code?: string,
  details?: unknown
): ApiError {
  return new ApiError(statusCode, message, code, details)
}

/**
 * Handle API errors consistently
 * Converts various error types to H3 errors with proper status codes
 *
 * @param error - The error to handle (can be ApiError, H3Error, or unknown)
 * @returns H3Error ready to be thrown
 *
 * @example
 * export default defineEventHandler(async (event) => {
 *   try {
 *     // ... logic
 *   } catch (error) {
 *     throw handleApiError(error)
 *   }
 * })
 */
export function handleApiError(error: unknown): H3Error {
  // If it's already an ApiError, convert to H3Error
  if (error instanceof ApiError) {
    return createError({
      statusCode: error.statusCode,
      message: error.message,
      data: error.toJSON()
    })
  }

  // If it's already an H3Error, return as-is
  if (error && typeof error === 'object' && 'statusCode' in error) {
    return error as H3Error
  }

  // Log unexpected errors for debugging
  const isProduction = process.env.NODE_ENV === 'production'
  if (!isProduction) {
    console.error('Unexpected error:', error)
  }

  // Return generic 500 error
  return createError({
    statusCode: 500,
    message: 'Internal server error',
    data: {
      success: false,
      error: 'Internal server error',
      statusCode: 500
    }
  })
}

/**
 * Common error codes for consistent error handling
 */
export const ErrorCodes = {
  UNAUTHORIZED: 'UNAUTHORIZED',
  FORBIDDEN: 'FORBIDDEN',
  NOT_FOUND: 'NOT_FOUND',
  VALIDATION_ERROR: 'VALIDATION_ERROR',
  INTERNAL_ERROR: 'INTERNAL_ERROR',
  BAD_REQUEST: 'BAD_REQUEST'
} as const

/**
 * Helper functions for common error scenarios
 */
export const ApiErrors = {
  unauthorized: (message = 'Unauthorized') =>
    createApiError(401, message, ErrorCodes.UNAUTHORIZED),

  forbidden: (message = 'Forbidden') =>
    createApiError(403, message, ErrorCodes.FORBIDDEN),

  notFound: (message = 'Not found') =>
    createApiError(404, message, ErrorCodes.NOT_FOUND),

  validationError: (message = 'Validation failed', details?: unknown) =>
    createApiError(400, message, ErrorCodes.VALIDATION_ERROR, details),

  badRequest: (message = 'Bad request', details?: unknown) =>
    createApiError(400, message, ErrorCodes.BAD_REQUEST, details),

  internalError: (message = 'Internal server error') =>
    createApiError(500, message, ErrorCodes.INTERNAL_ERROR)
}
