/// Classes d'échec pour la gestion d'erreurs structurée abstract class Failure { final String message; final String? code; final Map? details; const Failure({ required this.message, this.code, this.details, }); @override String toString() => 'Failure(message: $message, code: $code)'; @override bool operator ==(Object other) { if (identical(this, other)) return true; return other is Failure && other.message == message && other.code == code; } @override int get hashCode => message.hashCode ^ code.hashCode; } /// Échec réseau (problèmes de connectivité, timeout, etc.) class NetworkFailure extends Failure { const NetworkFailure({ required super.message, super.code, super.details, }); factory NetworkFailure.noConnection() { return const NetworkFailure( message: 'Aucune connexion internet disponible', code: 'NO_CONNECTION', ); } factory NetworkFailure.timeout() { return const NetworkFailure( message: 'Délai d\'attente dépassé', code: 'TIMEOUT', ); } factory NetworkFailure.serverUnreachable() { return const NetworkFailure( message: 'Serveur inaccessible', code: 'SERVER_UNREACHABLE', ); } } /// Échec serveur (erreurs HTTP 5xx, erreurs API, etc.) class ServerFailure extends Failure { final int? statusCode; const ServerFailure({ required super.message, super.code, super.details, this.statusCode, }); factory ServerFailure.internalError() { return const ServerFailure( message: 'Erreur interne du serveur', code: 'INTERNAL_ERROR', statusCode: 500, ); } factory ServerFailure.serviceUnavailable() { return const ServerFailure( message: 'Service temporairement indisponible', code: 'SERVICE_UNAVAILABLE', statusCode: 503, ); } factory ServerFailure.badGateway() { return const ServerFailure( message: 'Passerelle défaillante', code: 'BAD_GATEWAY', statusCode: 502, ); } } /// Échec de validation (données invalides, contraintes non respectées) class ValidationFailure extends Failure { final Map>? fieldErrors; const ValidationFailure({ required super.message, super.code, super.details, this.fieldErrors, }); factory ValidationFailure.invalidData(String field, String error) { return ValidationFailure( message: 'Données invalides', code: 'INVALID_DATA', fieldErrors: {field: [error]}, ); } factory ValidationFailure.requiredField(String field) { return ValidationFailure( message: 'Champ requis manquant', code: 'REQUIRED_FIELD', fieldErrors: {field: ['Ce champ est requis']}, ); } factory ValidationFailure.multipleErrors(Map> errors) { return ValidationFailure( message: 'Plusieurs erreurs de validation', code: 'MULTIPLE_ERRORS', fieldErrors: errors, ); } } /// Échec d'authentification (login, permissions, tokens expirés) class AuthFailure extends Failure { const AuthFailure({ required super.message, super.code, super.details, }); factory AuthFailure.invalidCredentials() { return const AuthFailure( message: 'Identifiants invalides', code: 'INVALID_CREDENTIALS', ); } factory AuthFailure.tokenExpired() { return const AuthFailure( message: 'Session expirée, veuillez vous reconnecter', code: 'TOKEN_EXPIRED', ); } factory AuthFailure.insufficientPermissions() { return const AuthFailure( message: 'Permissions insuffisantes', code: 'INSUFFICIENT_PERMISSIONS', ); } factory AuthFailure.accountLocked() { return const AuthFailure( message: 'Compte verrouillé', code: 'ACCOUNT_LOCKED', ); } } /// Échec de données (ressource non trouvée, conflit, etc.) class DataFailure extends Failure { const DataFailure({ required super.message, super.code, super.details, }); factory DataFailure.notFound(String resource) { return DataFailure( message: '$resource non trouvé(e)', code: 'NOT_FOUND', details: {'resource': resource}, ); } factory DataFailure.alreadyExists(String resource) { return DataFailure( message: '$resource existe déjà', code: 'ALREADY_EXISTS', details: {'resource': resource}, ); } factory DataFailure.conflict(String reason) { return DataFailure( message: 'Conflit de données : $reason', code: 'CONFLICT', details: {'reason': reason}, ); } } /// Échec de cache (données expirées, cache corrompu) class CacheFailure extends Failure { const CacheFailure({ required super.message, super.code, super.details, }); factory CacheFailure.expired() { return const CacheFailure( message: 'Données en cache expirées', code: 'CACHE_EXPIRED', ); } factory CacheFailure.corrupted() { return const CacheFailure( message: 'Cache corrompu', code: 'CACHE_CORRUPTED', ); } } /// Échec de fichier (lecture, écriture, format) class FileFailure extends Failure { const FileFailure({ required super.message, super.code, super.details, }); factory FileFailure.notFound(String filePath) { return FileFailure( message: 'Fichier non trouvé', code: 'FILE_NOT_FOUND', details: {'filePath': filePath}, ); } factory FileFailure.accessDenied(String filePath) { return FileFailure( message: 'Accès au fichier refusé', code: 'ACCESS_DENIED', details: {'filePath': filePath}, ); } factory FileFailure.invalidFormat(String expectedFormat) { return FileFailure( message: 'Format de fichier invalide', code: 'INVALID_FORMAT', details: {'expectedFormat': expectedFormat}, ); } } /// Échec générique pour les cas non spécifiés class UnknownFailure extends Failure { const UnknownFailure({ required super.message, super.code, super.details, }); factory UnknownFailure.fromException(Exception exception) { return UnknownFailure( message: 'Erreur inattendue : ${exception.toString()}', code: 'UNKNOWN_ERROR', details: {'exception': exception.toString()}, ); } }