import { AxiosError } from 'axios';
import toast from 'react-hot-toast';

/**
 * Standard error response from backend
 */
interface BackendError {
  statusCode: number;
  message: string | string[];
  error: string;
  details?: any;
  conflicts?: any[];
}

/**
 * Error handling utility for consistent error messages across the app
 */
export class ErrorHandler {
  /**
   * Extract user-friendly error message from various error types
   */
  static getMessage(error: unknown, fallback: string = 'An error occurred'): string {
    // Axios error with backend response
    if (this.isAxiosError(error) && error.response?.data) {
      const data = error.response.data as BackendError;

      // Handle array of messages
      if (Array.isArray(data.message)) {
        return data.message.join(', ');
      }

      // Handle single message
      if (data.message) {
        return data.message;
      }

      // Handle specific status codes
      if (error.response.status === 401) {
        return 'Authentication required. Please log in again.';
      }
      if (error.response.status === 403) {
        return 'You do not have permission to perform this action.';
      }
      if (error.response.status === 404) {
        return 'The requested resource was not found.';
      }
      if (error.response.status === 409) {
        return 'A conflict occurred. Please check for overlapping schedules.';
      }
      if (error.response.status >= 500) {
        return 'Server error. Please try again later.';
      }
    }

    // Axios error without response (network error)
    if (this.isAxiosError(error) && !error.response) {
      return 'Network error. Please check your connection.';
    }

    // Standard Error object
    if (error instanceof Error) {
      return error.message;
    }

    // Unknown error type
    return fallback;
  }

  /**
   * Show error toast with extracted message
   */
  static showError(error: unknown, fallback?: string): void {
    const message = this.getMessage(error, fallback);
    toast.error(message);
  }

  /**
   * Log error to console with context
   */
  static log(context: string, error: unknown, additionalInfo?: any): void {
    const timestamp = new Date().toISOString();
    const message = this.getMessage(error);

    console.error(`[${timestamp}] [${context}] ${message}`);

    if (this.isAxiosError(error)) {
      console.error('Request:', {
        method: error.config?.method?.toUpperCase(),
        url: error.config?.url,
        data: error.config?.data,
      });
      console.error('Response:', error.response?.data);
    } else {
      console.error('Error details:', error);
    }

    if (additionalInfo) {
      console.error('Additional info:', additionalInfo);
    }
  }

  /**
   * Handle error with both toast and logging
   */
  static handle(context: string, error: unknown, fallback?: string, additionalInfo?: any): void {
    this.log(context, error, additionalInfo);
    this.showError(error, fallback);
  }

  /**
   * Type guard for AxiosError
   */
  private static isAxiosError(error: unknown): error is AxiosError {
    return (error as AxiosError)?.isAxiosError === true;
  }

  /**
   * Extract conflict details if present
   */
  static getConflicts(error: unknown): any[] | null {
    if (this.isAxiosError(error) && error.response?.data) {
      const data = error.response.data as BackendError;
      return data.conflicts || null;
    }
    return null;
  }

  /**
   * Check if error is a specific status code
   */
  static isStatus(error: unknown, statusCode: number): boolean {
    return this.isAxiosError(error) && error.response?.status === statusCode;
  }

  /**
   * Check if error is authentication-related
   */
  static isAuthError(error: unknown): boolean {
    return this.isStatus(error, 401) || this.isStatus(error, 403);
  }

  /**
   * Check if error is a conflict (409)
   */
  static isConflict(error: unknown): boolean {
    return this.isStatus(error, 409);
  }

  /**
   * Check if error is validation-related (400)
   */
  static isValidationError(error: unknown): boolean {
    return this.isStatus(error, 400);
  }
}

/**
 * Convenience function for handling errors in try-catch blocks
 *
 * @example
 * try {
 *   await api.createVIP(data);
 *   toast.success('VIP created successfully');
 * } catch (error) {
 *   handleError('VIP Creation', error, 'Failed to create VIP');
 * }
 */
export function handleError(context: string, error: unknown, fallback?: string, additionalInfo?: any): void {
  ErrorHandler.handle(context, error, fallback, additionalInfo);
}
