import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';

/// 에러 처리 표준화를 위한 유틸리티 클래스
class ErrorHandler {
  /// API 호출을 감싸서 일관된 에러 처리를 제공하는 wrapper 함수
  /// 
  /// 사용 예시:
  /// ```dart
  /// final result = await ErrorHandler.handleApiCall(
  ///   () => apiService.getData(),
  ///   onError: (failure) => print('Error: ${failure.message}'),
  /// );
  /// ```
  static Future<T?> handleApiCall<T>(
    Future<T> Function() apiCall, {
    Function(AppFailure)? onError,
    bool showErrorDialog = true,
  }) async {
    try {
      return await apiCall();
    } on DioException catch (e) {
      final failure = _handleDioError(e);
      if (onError != null) {
        onError(failure);
      }
      if (kDebugMode) {
        print('API Error: ${failure.message}');
        print('Stack trace: ${e.stackTrace}');
      }
      return null;
    } on FormatException catch (e) {
      final failure = DataParseFailure(
        message: '데이터 형식 오류: ${e.message}',
      );
      if (onError != null) {
        onError(failure);
      }
      return null;
    } catch (e, stackTrace) {
      final failure = UnexpectedFailure(
        message: '예상치 못한 오류가 발생했습니다: ${e.toString()}',
      );
      if (onError != null) {
        onError(failure);
      }
      if (kDebugMode) {
        print('Unexpected Error: $e');
        print('Stack trace: $stackTrace');
      }
      return null;
    }
  }

  /// DioException을 AppFailure로 변환
  static AppFailure _handleDioError(DioException error) {
    switch (error.type) {
      case DioExceptionType.connectionTimeout:
      case DioExceptionType.sendTimeout:
      case DioExceptionType.receiveTimeout:
        return NetworkFailure(
          message: '네트워크 연결 시간이 초과되었습니다.',
          statusCode: null,
        );
      
      case DioExceptionType.badResponse:
        final statusCode = error.response?.statusCode;
        final responseData = error.response?.data;
        String message = '서버 오류가 발생했습니다.';
        
        // 서버에서 전달한 에러 메시지가 있으면 사용
        if (responseData != null) {
          if (responseData is Map && responseData.containsKey('message')) {
            message = responseData['message'];
          } else if (responseData is String) {
            message = responseData;
          }
        }
        
        // 상태 코드별 메시지 처리
        switch (statusCode) {
          case 400:
            return ValidationFailure(
              message: message.isNotEmpty ? message : '잘못된 요청입니다.',
              statusCode: statusCode,
            );
          case 401:
            return AuthenticationFailure(
              message: '인증이 필요합니다. 다시 로그인해주세요.',
              statusCode: statusCode,
            );
          case 403:
            return AuthorizationFailure(
              message: '이 작업을 수행할 권한이 없습니다.',
              statusCode: statusCode,
            );
          case 404:
            return NotFoundFailure(
              message: '요청한 리소스를 찾을 수 없습니다.',
              statusCode: statusCode,
            );
          case 409:
            return ConflictFailure(
              message: message.isNotEmpty ? message : '중복된 데이터가 있습니다.',
              statusCode: statusCode,
            );
          case 422:
            return ValidationFailure(
              message: message.isNotEmpty ? message : '입력 데이터가 올바르지 않습니다.',
              statusCode: statusCode,
            );
          case 500:
          case 502:
          case 503:
          case 504:
            return ServerFailure(
              message: '서버 오류가 발생했습니다. 잠시 후 다시 시도해주세요.',
              statusCode: statusCode,
            );
          default:
            return ServerFailure(
              message: message,
              statusCode: statusCode,
            );
        }
      
      case DioExceptionType.cancel:
        return CancelledFailure(
          message: '요청이 취소되었습니다.',
        );
      
      case DioExceptionType.connectionError:
        return NetworkFailure(
          message: '네트워크 연결을 확인해주세요.',
          statusCode: null,
        );
      
      case DioExceptionType.badCertificate:
        return SecurityFailure(
          message: '보안 인증서 오류가 발생했습니다.',
        );
      
      case DioExceptionType.unknown:
        return UnexpectedFailure(
          message: error.message ?? '알 수 없는 오류가 발생했습니다.',
        );
    }
  }

  /// 에러 메시지를 사용자 친화적인 메시지로 변환
  static String getUserFriendlyMessage(AppFailure failure) {
    if (failure is NetworkFailure) {
      return '네트워크 연결을 확인해주세요.';
    } else if (failure is AuthenticationFailure) {
      return '로그인이 필요합니다.';
    } else if (failure is AuthorizationFailure) {
      return '권한이 없습니다.';
    } else if (failure is ValidationFailure) {
      return failure.message;
    } else if (failure is ServerFailure) {
      return '서버 오류가 발생했습니다. 잠시 후 다시 시도해주세요.';
    } else {
      return failure.message;
    }
  }
}

/// 기본 Failure 클래스
abstract class AppFailure {
  final String message;
  final int? statusCode;

  AppFailure({
    required this.message,
    this.statusCode,
  });

  @override
  String toString() => message;
}

/// 네트워크 관련 실패
class NetworkFailure extends AppFailure {
  NetworkFailure({
    required super.message,
    super.statusCode,
  });
}

/// 서버 관련 실패
class ServerFailure extends AppFailure {
  ServerFailure({
    required super.message,
    super.statusCode,
  });
}

/// 인증 실패 (401)
class AuthenticationFailure extends AppFailure {
  AuthenticationFailure({
    required super.message,
    super.statusCode,
  });
}

/// 권한 실패 (403)
class AuthorizationFailure extends AppFailure {
  AuthorizationFailure({
    required super.message,
    super.statusCode,
  });
}

/// 유효성 검증 실패 (400, 422)
class ValidationFailure extends AppFailure {
  ValidationFailure({
    required super.message,
    super.statusCode,
  });
}

/// 리소스를 찾을 수 없음 (404)
class NotFoundFailure extends AppFailure {
  NotFoundFailure({
    required super.message,
    super.statusCode,
  });
}

/// 충돌 발생 (409)
class ConflictFailure extends AppFailure {
  ConflictFailure({
    required super.message,
    super.statusCode,
  });
}

/// 데이터 파싱 실패
class DataParseFailure extends AppFailure {
  DataParseFailure({
    required super.message,
  });
}

/// 요청 취소됨
class CancelledFailure extends AppFailure {
  CancelledFailure({
    required super.message,
  });
}

/// 보안 관련 실패
class SecurityFailure extends AppFailure {
  SecurityFailure({
    required super.message,
  });
}

/// 예상치 못한 실패
class UnexpectedFailure extends AppFailure {
  UnexpectedFailure({
    required super.message,
  });
}

/// 에러 처리 결과를 담는 Result 타입
class Result<T> {
  final T? data;
  final AppFailure? failure;

  Result._({this.data, this.failure});

  factory Result.success(T data) => Result._(data: data);
  factory Result.failure(AppFailure failure) => Result._(failure: failure);

  bool get isSuccess => data != null;
  bool get isFailure => failure != null;

  R when<R>({
    required R Function(T data) success,
    required R Function(AppFailure failure) failure,
  }) {
    if (this.data != null) {
      return success(this.data as T);
    } else {
      return failure(this.failure!);
    }
  }
}