/// Base exception class for all application exceptions abstract class AppException implements Exception { final String message; final String? details; final StackTrace? stackTrace; AppException(this.message, [this.details, this.stackTrace]); @override String toString() { if (details != null) { return '$runtimeType: $message\nDetails: $details'; } return '$runtimeType: $message'; } } /// Exception thrown when network operations fail class NetworkException extends AppException { final int? statusCode; final String? url; NetworkException( super.message, [ super.details, super.stackTrace, this.statusCode, this.url, ]); @override String toString() { final buffer = StringBuffer('NetworkException: $message'); if (statusCode != null) { buffer.write('\nStatus Code: $statusCode'); } if (url != null) { buffer.write('\nURL: $url'); } if (details != null) { buffer.write('\nDetails: $details'); } return buffer.toString(); } } /// Exception thrown when authentication fails class AuthenticationException extends AppException { final String? userId; final AuthenticationFailureReason? reason; AuthenticationException( super.message, [ super.details, super.stackTrace, this.userId, this.reason, ]); @override String toString() { final buffer = StringBuffer('AuthenticationException: $message'); if (userId != null) { buffer.write('\nUser ID: $userId'); } if (reason != null) { buffer.write('\nReason: ${reason!.name}'); } if (details != null) { buffer.write('\nDetails: $details'); } return buffer.toString(); } } /// Reasons for authentication failure enum AuthenticationFailureReason { invalidCredentials, sessionExpired, networkError, serverError, unknown, } /// Exception thrown when parsing fails class ParseException extends AppException { final String? source; final String? expectedFormat; ParseException( super.message, [ super.details, super.stackTrace, this.source, this.expectedFormat, ]); @override String toString() { final buffer = StringBuffer('ParseException: $message'); if (expectedFormat != null) { buffer.write('\nExpected Format: $expectedFormat'); } if (source != null && source!.length <= 100) { buffer.write('\nSource: $source'); } else if (source != null) { buffer.write('\nSource: ${source!.substring(0, 100)}...'); } if (details != null) { buffer.write('\nDetails: $details'); } return buffer.toString(); } } /// Exception thrown when validation fails class ValidationException extends AppException { final String? fieldName; final dynamic invalidValue; final List? validationRules; ValidationException( super.message, [ super.details, super.stackTrace, this.fieldName, this.invalidValue, this.validationRules, ]); @override String toString() { final buffer = StringBuffer('ValidationException: $message'); if (fieldName != null) { buffer.write('\nField: $fieldName'); } if (invalidValue != null) { buffer.write('\nInvalid Value: $invalidValue'); } if (validationRules != null && validationRules!.isNotEmpty) { buffer.write('\nValidation Rules: ${validationRules!.join(", ")}'); } if (details != null) { buffer.write('\nDetails: $details'); } return buffer.toString(); } }