/**
 * Enhanced Error Utilities for GridPilot
 * 
 * Provides comprehensive error handling, validation, and user-friendly error messages
 * for both end users and developers.
 */

import { ApiError } from '@/lib/api/base/ApiError';

export interface ValidationError {
  field: string;
  message: string;
  value?: unknown;
}

export interface EnhancedErrorContext {
  timestamp?: string;
  component?: string;
  action?: string;
  formData?: Record<string, unknown>;
  userId?: string;
  sessionId?: string;
}

/**
 * Parse API error response to extract validation errors or user-friendly messages
 */
export function parseApiError(error: unknown): {
  userMessage: string;
  developerMessage: string;
  validationErrors: ValidationError[];
  isValidationError: boolean;
} {
  const result = {
    userMessage: 'An unexpected error occurred',
    developerMessage: '',
    validationErrors: [] as ValidationError[],
    isValidationError: false,
  };

  if (error instanceof ApiError) {
    result.developerMessage = error.getDeveloperMessage();
    
    // Check if it's a validation error
    if (error.type === 'VALIDATION_ERROR') {
      result.isValidationError = true;
      result.userMessage = 'Please check your input and try again';
      
      // Try to parse validation details from response
      try {
        if (error.context.responseText) {
          const parsed = JSON.parse(error.context.responseText);
          
          // Handle NestJS validation error format
          if (parsed.message && Array.isArray(parsed.message)) {
            result.validationErrors = parsed.message.map((msg: unknown) => {
              const m = msg as { property?: string; field?: string; constraints?: Record<string, string>; message?: string; value?: unknown };
              return {
                field: m.property || m.field || 'unknown',
                message: m.constraints ? Object.values(m.constraints).join(', ') : m.message || 'Invalid value',
                value: m.value,
              };
            });
          } 
          // Handle custom error format
          else if (parsed.errors && Array.isArray(parsed.errors)) {
            result.validationErrors = parsed.errors.map((err: unknown) => {
              const e = err as { field?: string; property?: string; message?: string; value?: unknown };
              return {
                field: e.field || e.property || 'unknown',
                message: e.message || 'Invalid value',
                value: e.value,
              };
            });
          }
          // Handle single message
          else if (parsed.message && typeof parsed.message === 'string') {
            result.userMessage = parsed.message;
          }
        }
      } catch (e) {
        // If parsing fails, use default messages
      }
    } else {
      result.userMessage = error.getUserMessage();
    }
  } else if (error instanceof Error) {
    result.userMessage = error.message;
    result.developerMessage = error.message;
  } else {
    result.userMessage = 'An unknown error occurred';
    result.developerMessage = String(error);
  }

  return result;
}

/**
 * Format validation errors for display in forms
 */
export function formatValidationErrorsForForm(
  validationErrors: ValidationError[]
): Record<string, string> {
  const formErrors: Record<string, string> = {};
  
  validationErrors.forEach((error) => {
    // Map API field names to form field names
    const fieldName = mapApiFieldToFormField(error.field);
    formErrors[fieldName] = error.message;
  });
  
  return formErrors;
}

/**
 * Map API field names to form field names
 */
function mapApiFieldToFormField(apiField: string): string {
  const fieldMap: Record<string, string> = {
    'rememberMe': 'rememberMe',
    'email': 'email',
    'password': 'password',
    'displayName': 'displayName',
    'firstName': 'firstName',
    'lastName': 'lastName',
    'confirmPassword': 'confirmPassword',
    'role': 'role',
  };
  
  return fieldMap[apiField] || apiField;
}

/**
 * Create enhanced error context for debugging
 */
export function createErrorContext(
  error: unknown,
  context: EnhancedErrorContext
): EnhancedErrorContext {
  return {
    timestamp: new Date().toISOString(),
    ...context,
  };
}

/**
 * Check if error is retryable
 */
export function isRetryable(error: unknown): boolean {
  if (error instanceof ApiError) {
    return error.isRetryable();
  }
  return false;
}

/**
 * Check if error is a network connectivity issue
 */
export function isConnectivityError(error: unknown): boolean {
  if (error instanceof ApiError) {
    return error.isConnectivityIssue();
  }
  return false;
}

/**
 * Get error severity for logging and display
 */
export function getErrorSeverity(error: unknown): 'error' | 'warning' | 'info' {
  if (error instanceof ApiError) {
    const severity = error.getSeverity();
    if (severity === 'error') return 'error';
    if (severity === 'warn') return 'warning';
    return 'info';
  }
  return 'error';
}

/**
 * Create user-friendly error summary
 */
export function createUserErrorSummary(error: unknown): {
  title: string;
  description: string;
  action: string;
} {
  const parsed = parseApiError(error);
  
  if (parsed.isValidationError) {
    return {
      title: 'Invalid Input',
      description: parsed.userMessage,
      action: 'Please review your input and try again',
    };
  }
  
  if (isConnectivityError(error)) {
    return {
      title: 'Connection Issue',
      description: 'Unable to connect to the server',
      action: 'Check your internet connection and try again',
    };
  }
  
  if (isRetryable(error)) {
    return {
      title: 'Temporary Issue',
      description: parsed.userMessage,
      action: 'Please try again in a moment',
    };
  }
  
  return {
    title: 'Error',
    description: parsed.userMessage,
    action: 'Please try again or contact support if the issue persists',
  };
}

/**
 * Log error with context (only in development)
 */
export function logErrorWithContext(
  error: unknown,
  context: EnhancedErrorContext
): void {
  if (process.env.NODE_ENV !== 'development') return;
  
  const parsed = parseApiError(error);
  const severity = getErrorSeverity(error);
  
  console.group(`🚨 [${severity.toUpperCase()}] ${context.component || 'Unknown'} - ${context.action || 'Unknown action'}`);
  console.error('User Message:', parsed.userMessage);
  console.error('Developer Message:', parsed.developerMessage);
  if (parsed.validationErrors.length > 0) {
    console.error('Validation Errors:', parsed.validationErrors);
  }
  if (context.formData) {
    console.error('Form Data:', context.formData);
  }
  console.error('Context:', context);
  console.error('Original Error:', error);
  console.groupEnd();
}

/**
 * Delay execution for retry logic
 */
export async function delay(ms: number): Promise<void> {
  await new Promise(resolve => setTimeout(resolve, ms));
}

/**
 * Retry operation with exponential backoff
 */
export async function retryWithBackoff<T>(
  operation: () => Promise<T>,
  maxRetries: number = 3,
  baseDelay: number = 1000
): Promise<T> {
  let lastError: unknown;
  
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await operation();
    } catch (error) {
      lastError = error;
      
      if (attempt === maxRetries || !isRetryable(error)) {
        throw error;
      }
      
      // Exponential backoff: 1s, 2s, 4s
      const delayMs = baseDelay * Math.pow(2, attempt);
      await delay(delayMs);
    }
  }
  
  throw lastError;
}