/// Custom exceptions for the Worker app
///
/// This file defines all custom exception types used throughout the application
/// for better error handling and user feedback.
library;

// ============================================================================
// Network Exceptions
// ============================================================================

/// Base exception for all network-related errors
class NetworkException implements Exception {
  const NetworkException(this.message, {this.statusCode, this.data});

  final String message;
  final int? statusCode;
  final dynamic data;

  @override
  String toString() =>
      'NetworkException: $message${statusCode != null ? ' (Status: $statusCode)' : ''}';
}

/// Exception thrown when there's no internet connection
class NoInternetException extends NetworkException {
  const NoInternetException()
    : super('Không có kết nối internet. Vui lòng kiểm tra kết nối của bạn.');
}

/// Exception thrown when connection times out
class TimeoutException extends NetworkException {
  const TimeoutException()
    : super('Kết nối quá lâu. Vui lòng thử lại.', statusCode: 408);
}

/// Exception thrown when server returns 500+ errors
class ServerException extends NetworkException {
  const ServerException([
    String message = 'Lỗi máy chủ. Vui lòng thử lại sau.',
    int? statusCode,
  ]) : super(message, statusCode: statusCode);
}

/// Exception thrown when server is unreachable
class ServiceUnavailableException extends ServerException {
  const ServiceUnavailableException()
    : super('Dịch vụ tạm thời không khả dụng. Vui lòng thử lại sau.', 503);
}

// ============================================================================
// Authentication Exceptions
// ============================================================================

/// Base exception for authentication-related errors
class AuthException implements Exception {
  const AuthException(this.message, {this.statusCode});

  final String message;
  final int? statusCode;

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

/// Exception thrown when authentication credentials are invalid
class InvalidCredentialsException extends AuthException {
  const InvalidCredentialsException()
    : super('Thông tin đăng nhập không hợp lệ.', statusCode: 401);
}

/// Exception thrown when user is not authenticated
class UnauthorizedException extends AuthException {
  const UnauthorizedException([
    super.message = 'Phiên đăng nhập hết hạn. Vui lòng đăng nhập lại.',
  ]) : super(statusCode: 401);
}

/// Exception thrown when user doesn't have permission
class ForbiddenException extends AuthException {
  const ForbiddenException()
    : super('Bạn không có quyền truy cập tài nguyên này.', statusCode: 403);
}

/// Exception thrown when auth token is expired
class TokenExpiredException extends AuthException {
  const TokenExpiredException()
    : super(
        'Phiên đăng nhập hết hạn. Vui lòng đăng nhập lại.',
        statusCode: 401,
      );
}

/// Exception thrown when refresh token is invalid
class InvalidRefreshTokenException extends AuthException {
  const InvalidRefreshTokenException()
    : super(
        'Không thể làm mới phiên đăng nhập. Vui lòng đăng nhập lại.',
        statusCode: 401,
      );
}

/// Exception thrown when OTP is invalid
class InvalidOTPException extends AuthException {
  const InvalidOTPException()
    : super('Mã OTP không hợp lệ. Vui lòng thử lại.', statusCode: 400);
}

/// Exception thrown when OTP is expired
class OTPExpiredException extends AuthException {
  const OTPExpiredException()
    : super('Mã OTP đã hết hạn. Vui lòng yêu cầu mã mới.', statusCode: 400);
}

// ============================================================================
// Request Validation Exceptions
// ============================================================================

/// Exception thrown when request data is invalid
class ValidationException implements Exception {
  const ValidationException(this.message, {this.errors});

  final String message;
  final Map<String, List<String>>? errors;

  @override
  String toString() {
    if (errors != null && errors!.isNotEmpty) {
      final errorMessages = errors!.entries
          .map((e) => '${e.key}: ${e.value.join(", ")}')
          .join('; ');
      return 'ValidationException: $message - $errorMessages';
    }
    return 'ValidationException: $message';
  }
}

/// Exception thrown when request parameters are invalid
class BadRequestException extends ValidationException {
  const BadRequestException([
    String message = 'Yêu cầu không hợp lệ.',
    Map<String, List<String>>? errors,
  ]) : super(message, errors: errors);
}

// ============================================================================
// Resource Exceptions
// ============================================================================

/// Exception thrown when requested resource is not found
class NotFoundException implements Exception {
  const NotFoundException([
    this.message = 'Không tìm thấy tài nguyên.',
    this.resourceType,
    this.resourceId,
  ]);

  final String message;
  final String? resourceType;
  final String? resourceId;

  @override
  String toString() {
    if (resourceType != null && resourceId != null) {
      return 'NotFoundException: $resourceType with ID $resourceId not found';
    }
    return 'NotFoundException: $message';
  }
}

/// Exception thrown when trying to create a duplicate resource
class ConflictException implements Exception {
  const ConflictException([this.message = 'Tài nguyên đã tồn tại.']);

  final String message;

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

// ============================================================================
// Rate Limiting Exceptions
// ============================================================================

/// Exception thrown when API rate limit is exceeded
class RateLimitException implements Exception {
  const RateLimitException([
    this.message = 'Bạn đã gửi quá nhiều yêu cầu. Vui lòng thử lại sau.',
    this.retryAfter,
  ]);

  final String message;
  final int? retryAfter; // seconds

  @override
  String toString() {
    if (retryAfter != null) {
      return 'RateLimitException: $message (Retry after: ${retryAfter}s)';
    }
    return 'RateLimitException: $message';
  }
}

// ============================================================================
// Payment Exceptions
// ============================================================================

/// Exception thrown for payment-related errors
class PaymentException implements Exception {
  const PaymentException(this.message, {this.transactionId});

  final String message;
  final String? transactionId;

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

/// Exception thrown when payment fails
class PaymentFailedException extends PaymentException {
  const PaymentFailedException([
    String message = 'Thanh toán thất bại. Vui lòng thử lại.',
    String? transactionId,
  ]) : super(message, transactionId: transactionId);
}

/// Exception thrown when payment is cancelled
class PaymentCancelledException extends PaymentException {
  const PaymentCancelledException() : super('Thanh toán đã bị hủy.');
}

// ============================================================================
// Cache Exceptions
// ============================================================================

/// Exception thrown for cache-related errors
class CacheException implements Exception {
  const CacheException([this.message = 'Lỗi khi truy cập bộ nhớ đệm.']);

  final String message;

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

/// Exception thrown when cache data is corrupted
class CacheCorruptedException extends CacheException {
  const CacheCorruptedException() : super('Dữ liệu bộ nhớ đệm bị hỏng.');
}

// ============================================================================
// Storage Exceptions
// ============================================================================

/// Exception thrown for local storage errors
class StorageException implements Exception {
  const StorageException([this.message = 'Lỗi khi truy cập bộ nhớ cục bộ.']);

  final String message;

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

/// Exception thrown when storage is full
class StorageFullException extends StorageException {
  const StorageFullException()
    : super('Bộ nhớ đã đầy. Vui lòng giải phóng không gian.');
}

// ============================================================================
// Parse Exceptions
// ============================================================================

/// Exception thrown when JSON parsing fails
class ParseException implements Exception {
  const ParseException([
    this.message = 'Lỗi khi phân tích dữ liệu.',
    this.source,
  ]);

  final String message;
  final dynamic source;

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

// ============================================================================
// Unknown Exceptions
// ============================================================================

/// Exception thrown for unexpected errors
class UnknownException implements Exception {
  const UnknownException([
    this.message = 'Đã xảy ra lỗi không xác định.',
    this.originalError,
    this.stackTrace,
  ]);

  final String message;
  final dynamic originalError;
  final StackTrace? stackTrace;

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