/**
 * AI Error Classification Service
 *
 * Provides unified error handling and classification for all AI services.
 * Converts technical API errors into user-friendly messages.
 */

// ─── Error Types ─────────────────────────────────────────────────────────────

export type AIErrorType =
  | 'rate_limit'
  | 'quota_exceeded'
  | 'model_not_found'
  | 'invalid_api_key'
  | 'context_length'
  | 'parse_error'
  | 'timeout'
  | 'network_error'
  | 'content_filter'
  | 'server_error'
  | 'unknown'

export interface ClassifiedError {
  type: AIErrorType
  message: string
  originalMessage: string
  retryable: boolean
  suggestedAction?: string
}

// ─── Error Patterns ──────────────────────────────────────────────────────────

interface ErrorPattern {
  type: AIErrorType
  patterns: Array<string | RegExp>
  retryable: boolean
  userMessage: string
  suggestedAction?: string
}

const ERROR_PATTERNS: ErrorPattern[] = [
  {
    type: 'rate_limit',
    patterns: [
      'rate_limit',
      'rate limit',
      'too many requests',
      '429',
      'quota exceeded',
      'Rate limit reached',
    ],
    retryable: true,
    userMessage: 'Rate limit exceeded. Please wait a few minutes and try again.',
    suggestedAction: 'Wait 1-2 minutes before retrying, or reduce batch size.',
  },
  {
    type: 'quota_exceeded',
    patterns: [
      'insufficient_quota',
      'billing',
      'exceeded your current quota',
      'payment required',
      'account deactivated',
    ],
    retryable: false,
    userMessage: 'API quota exceeded. Please check your OpenAI billing settings.',
    suggestedAction: 'Add payment method or increase spending limit in OpenAI dashboard.',
  },
  {
    type: 'model_not_found',
    patterns: [
      'model_not_found',
      'does not exist',
      'The model',
      'invalid model',
      'model not available',
    ],
    retryable: false,
    userMessage: 'The selected AI model is not available. Please check your settings.',
    suggestedAction: 'Go to Settings → AI and select a different model.',
  },
  {
    type: 'invalid_api_key',
    patterns: [
      'invalid_api_key',
      'Incorrect API key',
      'authentication',
      'unauthorized',
      '401',
      'invalid api key',
    ],
    retryable: false,
    userMessage: 'Invalid API key. Please check your OpenAI API key in settings.',
    suggestedAction: 'Go to Settings → AI and enter a valid API key.',
  },
  {
    type: 'context_length',
    patterns: [
      'context_length',
      'maximum context length',
      'tokens',
      'too long',
      'reduce the length',
      'max_tokens',
    ],
    retryable: true,
    userMessage: 'Request too large. Try processing fewer items at once.',
    suggestedAction: 'Process items in smaller batches.',
  },
  {
    type: 'content_filter',
    patterns: [
      'content_filter',
      'content policy',
      'flagged',
      'inappropriate',
      'safety system',
    ],
    retryable: false,
    userMessage: 'Content was flagged by the AI safety system. Please review the input data.',
    suggestedAction: 'Check project descriptions for potentially sensitive content.',
  },
  {
    type: 'timeout',
    patterns: [
      'timeout',
      'timed out',
      'ETIMEDOUT',
      'ECONNABORTED',
      'deadline exceeded',
    ],
    retryable: true,
    userMessage: 'Request timed out. Please try again.',
    suggestedAction: 'Try again or process fewer items at once.',
  },
  {
    type: 'network_error',
    patterns: [
      'ENOTFOUND',
      'ECONNREFUSED',
      'network',
      'connection',
      'DNS',
      'getaddrinfo',
    ],
    retryable: true,
    userMessage: 'Network error. Please check your connection and try again.',
    suggestedAction: 'Check network connectivity and firewall settings.',
  },
  {
    type: 'server_error',
    patterns: [
      '500',
      '502',
      '503',
      '504',
      'internal error',
      'server error',
      'service unavailable',
    ],
    retryable: true,
    userMessage: 'OpenAI service temporarily unavailable. Please try again later.',
    suggestedAction: 'Wait a few minutes and retry. Check status.openai.com for outages.',
  },
]

// ─── Error Classification ────────────────────────────────────────────────────

/**
 * Classify an error from the OpenAI API
 */
export function classifyAIError(error: Error | unknown): ClassifiedError {
  const errorMessage = error instanceof Error ? error.message : String(error)
  const errorString = errorMessage.toLowerCase()

  // Check against known patterns
  for (const pattern of ERROR_PATTERNS) {
    for (const matcher of pattern.patterns) {
      const matches =
        typeof matcher === 'string'
          ? errorString.includes(matcher.toLowerCase())
          : matcher.test(errorString)

      if (matches) {
        return {
          type: pattern.type,
          message: pattern.userMessage,
          originalMessage: errorMessage,
          retryable: pattern.retryable,
          suggestedAction: pattern.suggestedAction,
        }
      }
    }
  }

  // Unknown error
  return {
    type: 'unknown',
    message: 'An unexpected error occurred. Please try again.',
    originalMessage: errorMessage,
    retryable: true,
    suggestedAction: 'If the problem persists, check the AI settings or contact support.',
  }
}

/**
 * Check if an error is a JSON parse error
 */
export function isParseError(error: Error | unknown): boolean {
  const message = error instanceof Error ? error.message : String(error)
  return (
    message.includes('JSON') ||
    message.includes('parse') ||
    message.includes('Unexpected token') ||
    message.includes('SyntaxError')
  )
}

/**
 * Create a classified parse error
 */
export function createParseError(originalMessage: string): ClassifiedError {
  return {
    type: 'parse_error',
    message: 'AI returned an invalid response. Items flagged for manual review.',
    originalMessage,
    retryable: true,
    suggestedAction: 'Review flagged items manually. Consider using a different model.',
  }
}

// ─── User-Friendly Messages ──────────────────────────────────────────────────

const USER_FRIENDLY_MESSAGES: Record<AIErrorType, string> = {
  rate_limit: 'Rate limit exceeded. Please wait a few minutes and try again.',
  quota_exceeded: 'API quota exceeded. Please check your OpenAI billing settings.',
  model_not_found: 'Selected AI model is not available. Please check your settings.',
  invalid_api_key: 'Invalid API key. Please verify your OpenAI API key.',
  context_length: 'Request too large. Please try with fewer items.',
  parse_error: 'AI response could not be processed. Items flagged for review.',
  timeout: 'Request timed out. Please try again.',
  network_error: 'Network connection error. Please check your connection.',
  content_filter: 'Content flagged by AI safety system. Please review input data.',
  server_error: 'AI service temporarily unavailable. Please try again later.',
  unknown: 'An unexpected error occurred. Please try again.',
}

/**
 * Get a user-friendly message for an error type
 */
export function getUserFriendlyMessage(errorType: AIErrorType): string {
  return USER_FRIENDLY_MESSAGES[errorType]
}

// ─── Error Handling Helpers ──────────────────────────────────────────────────

/**
 * Wrap an async function with standardized AI error handling
 */
export async function withAIErrorHandling<T>(
  fn: () => Promise<T>,
  fallback: T
): Promise<{ result: T; error?: ClassifiedError }> {
  try {
    const result = await fn()
    return { result }
  } catch (error) {
    const classified = classifyAIError(error)
    console.error(`[AI Error] ${classified.type}:`, classified.originalMessage)
    return { result: fallback, error: classified }
  }
}

/**
 * Log an AI error with context
 */
export function logAIError(
  service: string,
  operation: string,
  error: ClassifiedError,
  context?: Record<string, unknown>
): void {
  console.error(
    `[AI ${service}] ${operation} failed:`,
    JSON.stringify({
      type: error.type,
      message: error.message,
      originalMessage: error.originalMessage,
      retryable: error.retryable,
      ...context,
    })
  )
}

// ─── Retry Logic ─────────────────────────────────────────────────────────────

/**
 * Determine if an operation should be retried based on error type
 */
export function shouldRetry(error: ClassifiedError, attempt: number, maxAttempts: number = 3): boolean {
  if (!error.retryable) return false
  if (attempt >= maxAttempts) return false

  // Rate limits need longer delays
  if (error.type === 'rate_limit') {
    return attempt < 2 // Only retry once for rate limits
  }

  return true
}

/**
 * Calculate delay before retry (exponential backoff)
 */
export function getRetryDelay(error: ClassifiedError, attempt: number): number {
  const baseDelay = error.type === 'rate_limit' ? 30000 : 1000 // 30s for rate limit, 1s otherwise
  return baseDelay * Math.pow(2, attempt)
}
