/// Gestionnaire d'erreurs global pour l'application
library error_handler;

import 'package:dio/dio.dart';

/// Classe utilitaire pour gérer les erreurs de manière centralisée
class ErrorHandler {
  /// Convertit une erreur en message utilisateur lisible
  static String getErrorMessage(dynamic error) {
    if (error is DioException) {
      return _handleDioError(error);
    } else if (error is String) {
      return error;
    } else if (error is Exception) {
      return error.toString().replaceAll('Exception: ', '');
    }
    return 'Une erreur inattendue s\'est produite.';
  }

  /// Gère les erreurs Dio spécifiques
  static String _handleDioError(DioException error) {
    switch (error.type) {
      case DioExceptionType.connectionTimeout:
        return 'Délai de connexion dépassé.\nVérifiez votre connexion internet.';
      
      case DioExceptionType.sendTimeout:
        return 'Délai d\'envoi dépassé.\nVérifiez votre connexion internet.';
      
      case DioExceptionType.receiveTimeout:
        return 'Délai de réception dépassé.\nLe serveur met trop de temps à répondre.';
      
      case DioExceptionType.badResponse:
        return _handleBadResponse(error.response);
      
      case DioExceptionType.cancel:
        return 'Requête annulée.';
      
      case DioExceptionType.connectionError:
        return 'Erreur de connexion.\nVérifiez votre connexion internet.';
      
      case DioExceptionType.badCertificate:
        return 'Erreur de certificat SSL.\nLa connexion n\'est pas sécurisée.';
      
      case DioExceptionType.unknown:
      default:
        if (error.message?.contains('SocketException') ?? false) {
          return 'Impossible de se connecter au serveur.\nVérifiez votre connexion internet.';
        }
        return 'Erreur de connexion.\nVeuillez réessayer.';
    }
  }

  /// Gère les réponses HTTP avec erreur
  static String _handleBadResponse(Response? response) {
    if (response == null) {
      return 'Erreur serveur inconnue.';
    }

    // Essayer d'extraire le message d'erreur du body
    String? errorMessage;
    if (response.data is Map) {
      errorMessage = response.data['message'] ?? 
                     response.data['error'] ?? 
                     response.data['details'];
    }

    switch (response.statusCode) {
      case 400:
        return errorMessage ?? 'Requête invalide.\nVérifiez les données saisies.';
      
      case 401:
        return errorMessage ?? 'Non authentifié.\nVeuillez vous reconnecter.';
      
      case 403:
        return errorMessage ?? 'Accès refusé.\nVous n\'avez pas les permissions nécessaires.';
      
      case 404:
        return errorMessage ?? 'Ressource non trouvée.';
      
      case 409:
        return errorMessage ?? 'Conflit.\nCette ressource existe déjà.';
      
      case 422:
        return errorMessage ?? 'Données invalides.\nVérifiez les informations saisies.';
      
      case 429:
        return 'Trop de requêtes.\nVeuillez patienter quelques instants.';
      
      case 500:
        return errorMessage ?? 'Erreur serveur interne.\nVeuillez réessayer plus tard.';
      
      case 502:
        return 'Passerelle incorrecte.\nLe serveur est temporairement indisponible.';
      
      case 503:
        return 'Service temporairement indisponible.\nVeuillez réessayer plus tard.';
      
      case 504:
        return 'Délai d\'attente de la passerelle dépassé.\nLe serveur met trop de temps à répondre.';
      
      default:
        return errorMessage ?? 'Erreur serveur (${response.statusCode}).\nVeuillez réessayer.';
    }
  }

  /// Détermine si l'erreur est une erreur réseau
  static bool isNetworkError(dynamic error) {
    if (error is DioException) {
      return error.type == DioExceptionType.connectionTimeout ||
             error.type == DioExceptionType.sendTimeout ||
             error.type == DioExceptionType.receiveTimeout ||
             error.type == DioExceptionType.connectionError ||
             (error.message?.contains('SocketException') ?? false);
    }
    return false;
  }

  /// Détermine si l'erreur est une erreur d'authentification
  static bool isAuthError(dynamic error) {
    if (error is DioException && error.response != null) {
      return error.response!.statusCode == 401;
    }
    return false;
  }

  /// Détermine si l'erreur est une erreur de permissions
  static bool isPermissionError(dynamic error) {
    if (error is DioException && error.response != null) {
      return error.response!.statusCode == 403;
    }
    return false;
  }

  /// Détermine si l'erreur est une erreur de validation
  static bool isValidationError(dynamic error) {
    if (error is DioException && error.response != null) {
      return error.response!.statusCode == 400 || 
             error.response!.statusCode == 422;
    }
    return false;
  }

  /// Détermine si l'erreur est une erreur serveur
  static bool isServerError(dynamic error) {
    if (error is DioException && error.response != null) {
      final statusCode = error.response!.statusCode ?? 0;
      return statusCode >= 500 && statusCode < 600;
    }
    return false;
  }

  /// Extrait les détails de validation d'une erreur
  static Map<String, dynamic>? getValidationErrors(dynamic error) {
    if (error is DioException && 
        error.response != null && 
        error.response!.data is Map) {
      final data = error.response!.data as Map;
      if (data.containsKey('errors')) {
        return data['errors'] as Map<String, dynamic>?;
      }
      if (data.containsKey('validationErrors')) {
        return data['validationErrors'] as Map<String, dynamic>?;
      }
    }
    return null;
  }
}

/// Extension pour faciliter l'utilisation de ErrorHandler
extension ErrorHandlerExtension on Object {
  /// Convertit l'objet en message d'erreur lisible
  String toErrorMessage() => ErrorHandler.getErrorMessage(this);
  
  /// Vérifie si c'est une erreur réseau
  bool get isNetworkError => ErrorHandler.isNetworkError(this);
  
  /// Vérifie si c'est une erreur d'authentification
  bool get isAuthError => ErrorHandler.isAuthError(this);
  
  /// Vérifie si c'est une erreur de permissions
  bool get isPermissionError => ErrorHandler.isPermissionError(this);
  
  /// Vérifie si c'est une erreur de validation
  bool get isValidationError => ErrorHandler.isValidationError(this);
  
  /// Vérifie si c'est une erreur serveur
  bool get isServerError => ErrorHandler.isServerError(this);
  
  /// Récupère les erreurs de validation
  Map<String, dynamic>? get validationErrors => ErrorHandler.getValidationErrors(this);
}

