/// Exception de base pour toutes les exceptions serveur.
///
/// Cette exception est levée lorsque le serveur retourne une erreur
/// ou lorsqu'une communication avec le serveur échoue.
///
/// **Usage:**
/// ```dart
/// if (response.statusCode >= 400) {
///   throw ServerException(
///     'Erreur serveur: ${response.statusCode}',
///     statusCode: response.statusCode,
///   );
/// }
/// ```
class ServerException implements Exception {
  /// Crée une nouvelle [ServerException].
  ///
  /// [message] Message décrivant l'erreur
  /// [statusCode] Code de statut HTTP optionnel
  /// [originalError] L'erreur originale si disponible
  const ServerException(
    this.message, {
    this.statusCode,
    this.originalError,
  });

  /// Message décrivant l'erreur
  final String message;

  /// Code de statut HTTP (404, 500, etc.)
  final int? statusCode;

  /// L'erreur originale qui a causé cette exception
  final Object? originalError;

  @override
  String toString() {
    final buffer = StringBuffer('ServerException: $message');
    if (statusCode != null) {
      buffer.write(' (Status: $statusCode)');
    }
    if (originalError != null) {
      buffer.write(' (Original: $originalError)');
    }
    return buffer.toString();
  }
}

/// Exception liée au cache local.
///
/// Cette exception est levée lorsque :
/// - Les données ne peuvent pas être lues depuis le cache
/// - Les données ne peuvent pas être écrites dans le cache
/// - Le cache est corrompu ou inaccessible
///
/// **Usage:**
/// ```dart
/// try {
///   await cache.write(key, value);
/// } catch (e) {
///   throw CacheException('Impossible d\'écrire dans le cache', e);
/// }
/// ```
class CacheException implements Exception {
  /// Crée une nouvelle [CacheException].
  ///
  /// [message] Message décrivant l'erreur
  /// [originalError] L'erreur originale si disponible
  const CacheException([
    this.message = 'Erreur de cache',
    this.originalError,
  ]);

  /// Message décrivant l'erreur
  final String message;

  /// L'erreur originale qui a causé cette exception
  final Object? originalError;

  @override
  String toString() {
    if (originalError != null) {
      return 'CacheException: $message (Original: $originalError)';
    }
    return 'CacheException: $message';
  }
}

/// Exception liée à l'authentification.
///
/// Cette exception est levée lorsque :
/// - Les identifiants sont incorrects
/// - Le token d'authentification est expiré
/// - L'utilisateur n'est pas autorisé
///
/// **Usage:**
/// ```dart
/// if (!isValidCredentials(email, password)) {
///   throw AuthenticationException('Identifiants incorrects');
/// }
/// ```
class AuthenticationException implements Exception {
  /// Crée une nouvelle [AuthenticationException].
  ///
  /// [message] Message décrivant l'erreur d'authentification
  /// [code] Code d'erreur optionnel
  const AuthenticationException(
    this.message, {
    this.code,
  });

  /// Message décrivant l'erreur
  final String message;

  /// Code d'erreur optionnel
  final String? code;

  @override
  String toString() {
    if (code != null) {
      return 'AuthenticationException: $message (Code: $code)';
    }
    return 'AuthenticationException: $message';
  }
}

/// Exception serveur avec message personnalisé.
///
/// **Note:** Cette classe est dépréciée. Utilisez [ServerException] à la place.
///
/// **Usage déprécié:**
/// ```dart
/// throw ServerExceptionWithMessage('Erreur personnalisée');
/// ```
@Deprecated('Utilisez ServerException à la place')
class ServerExceptionWithMessage implements Exception {
  /// Crée une nouvelle [ServerExceptionWithMessage].
  ///
  /// [message] Message décrivant l'erreur
  const ServerExceptionWithMessage(this.message);

  /// Message décrivant l'erreur
  final String message;

  @override
  String toString() => 'ServerException: $message';
}

/// Exception levée lorsque l'utilisateur n'est pas trouvé.
///
/// Cette exception est levée lorsque :
/// - L'utilisateur avec l'ID donné n'existe pas
/// - L'utilisateur a été supprimé
/// - L'ID utilisateur est invalide
///
/// **Usage:**
/// ```dart
/// final user = await repository.getUserById(userId);
/// if (user == null) {
///   throw UserNotFoundException('Utilisateur avec ID $userId non trouvé');
/// }
/// ```
class UserNotFoundException implements Exception {
  /// Crée une nouvelle [UserNotFoundException].
  ///
  /// [message] Message décrivant l'erreur
  /// [userId] L'ID de l'utilisateur non trouvé
  const UserNotFoundException([
    this.message = 'Utilisateur non trouvé',
    this.userId,
  ]);

  /// Message décrivant l'erreur
  final String message;

  /// L'ID de l'utilisateur non trouvé
  final String? userId;

  @override
  String toString() {
    if (userId != null) {
      return 'UserNotFoundException: $message (UserId: $userId)';
    }
    return 'UserNotFoundException: $message';
  }
}

/// Exception levée en cas de conflit de données.
///
/// Cette exception est levée lorsque :
/// - Une ressource existe déjà (ex: email déjà utilisé)
/// - Une opération entre en conflit avec l'état actuel
/// - Une contrainte d'unicité est violée
///
/// **Usage:**
/// ```dart
/// if (await userExists(email)) {
///   throw ConflictException('Un utilisateur avec cet email existe déjà');
/// }
/// ```
class ConflictException implements Exception {
  /// Crée une nouvelle [ConflictException].
  ///
  /// [message] Message décrivant le conflit
  /// [resource] La ressource en conflit
  const ConflictException([
    this.message = 'Conflit détecté',
    this.resource,
  ]);

  /// Message décrivant le conflit
  final String message;

  /// La ressource en conflit
  final String? resource;

  @override
  String toString() {
    if (resource != null) {
      return 'ConflictException: $message (Resource: $resource)';
    }
    return 'ConflictException: $message';
  }
}

/// Exception levée lorsque l'utilisateur n'est pas autorisé.
///
/// Cette exception est levée lorsque :
/// - Le token d'authentification est invalide ou expiré
/// - L'utilisateur n'a pas les permissions nécessaires
/// - La session a expiré
///
/// **Usage:**
/// ```dart
/// if (!hasPermission(user, Permission.admin)) {
///   throw UnauthorizedException('Accès non autorisé');
/// }
/// ```
class UnauthorizedException implements Exception {
  /// Crée une nouvelle [UnauthorizedException].
  ///
  /// [message] Message décrivant l'erreur
  /// [reason] Raison de la non-autorisation
  const UnauthorizedException([
    this.message = 'Non autorisé',
    this.reason,
  ]);

  /// Message décrivant l'erreur
  final String message;

  /// Raison de la non-autorisation
  final String? reason;

  @override
  String toString() {
    if (reason != null) {
      return 'UnauthorizedException: $message (Reason: $reason)';
    }
    return 'UnauthorizedException: $message';
  }
}

/// Exception levée lorsque la validation échoue.
///
/// Cette exception est levée lorsque :
/// - Les données ne respectent pas les contraintes
/// - Les données sont manquantes ou invalides
/// - Les données ne passent pas la validation métier
///
/// **Usage:**
/// ```dart
/// if (email.isEmpty || !isValidEmail(email)) {
///   throw ValidationException('Email invalide', field: 'email');
/// }
/// ```
class ValidationException implements Exception {
  /// Crée une nouvelle [ValidationException].
  ///
  /// [message] Message décrivant l'erreur de validation
  /// [field] Le champ qui a échoué la validation
  const ValidationException(
    this.message, {
    this.field,
  });

  /// Message décrivant l'erreur
  final String message;

  /// Le champ qui a échoué la validation
  final String? field;

  @override
  String toString() {
    if (field != null) {
      return 'ValidationException: $message (Field: $field)';
    }
    return 'ValidationException: $message';
  }
}