import 'dart:io';

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import '../../../../core/errors/exceptions.dart';
import '../../../../core/constants/app_constants.dart';

/// 에러 처리 인터셉터
class ErrorInterceptor extends Interceptor {
  @override
  void onError(
    DioException err,
    ErrorInterceptorHandler handler,
  ) {
    // 에러 타입에 따른 처리
    switch (err.type) {
      case DioExceptionType.connectionTimeout:
      case DioExceptionType.sendTimeout:
      case DioExceptionType.receiveTimeout:
        handler.reject(
          DioException(
            requestOptions: err.requestOptions,
            error: NetworkException(
              message: AppConstants.timeoutError,
            ),
            type: err.type,
          ),
        );
        break;
        
      case DioExceptionType.connectionError:
        if (err.error is SocketException) {
          handler.reject(
            DioException(
              requestOptions: err.requestOptions,
              error: NetworkException(
                message: AppConstants.networkError,
              ),
              type: err.type,
            ),
          );
        } else {
          handler.reject(err);
        }
        break;
        
      case DioExceptionType.badResponse:
        _handleBadResponse(err, handler);
        break;
        
      case DioExceptionType.cancel:
        handler.reject(err);
        break;
        
      case DioExceptionType.badCertificate:
        handler.reject(
          DioException(
            requestOptions: err.requestOptions,
            error: NetworkException(
              message: '보안 인증서 오류가 발생했습니다.',
            ),
            type: err.type,
          ),
        );
        break;
        
      case DioExceptionType.unknown:
        // CORS 에러 감지 시도
        final errorMessage = err.message?.toLowerCase() ?? '';
        final errorString = err.error?.toString().toLowerCase() ?? '';
        
        if (errorMessage.contains('cors') || errorString.contains('cors') ||
            errorMessage.contains('xmlhttprequest') || errorString.contains('xmlhttprequest')) {
          debugPrint('[ErrorInterceptor] CORS 에러 감지됨');
          debugPrint('[ErrorInterceptor] 요청 URL: ${err.requestOptions.uri}');
          debugPrint('[ErrorInterceptor] 에러 메시지: ${err.message}');
          
          handler.reject(
            DioException(
              requestOptions: err.requestOptions,
              error: NetworkException(
                message: 'CORS 정책으로 인해 API 접근이 차단되었습니다.\n'
                    '개발 환경에서는 run_web_with_proxy.sh 스크립트를 사용하세요.',
              ),
              type: err.type,
            ),
          );
        } else {
          debugPrint('[ErrorInterceptor] 알 수 없는 에러');
          debugPrint('[ErrorInterceptor] 에러 타입: ${err.error?.runtimeType}');
          debugPrint('[ErrorInterceptor] 에러 메시지: ${err.message}');
          debugPrint('[ErrorInterceptor] 에러 내용: ${err.error}');
          
          handler.reject(
            DioException(
              requestOptions: err.requestOptions,
              error: ServerException(
                message: AppConstants.unknownError,
              ),
              type: err.type,
            ),
          );
        }
        break;
    }
  }
  
  /// 잘못된 응답 처리
  void _handleBadResponse(
    DioException err,
    ErrorInterceptorHandler handler,
  ) {
    final statusCode = err.response?.statusCode;
    final data = err.response?.data;
    
    String message = AppConstants.serverError;
    Map<String, dynamic>? errors;
    
    // API 응답에서 에러 메시지 추출
    if (data != null) {
      if (data is Map) {
        // error 필드가 객체인 경우 처리
        if (data['error'] is Map) {
          final errorObj = data['error'] as Map<String, dynamic>;
          message = errorObj['message'] ?? message;
          // code 필드도 저장 (필요시 사용)
          final errorCode = errorObj['code'];
          if (errorCode != null) {
            errors = {'code': errorCode};
          }
        } else {
          // 일반적인 경우: message 또는 error가 문자열
          message = data['message'] ?? 
                   (data['error'] is String ? data['error'] : null) ?? 
                   message;
        }
        
        // errors 필드가 있는 경우
        if (data['errors'] is Map) {
          errors = data['errors'] as Map<String, dynamic>?;
        }
      } else if (data is String) {
        message = data;
      }
    }
    
    // 상태 코드별 예외 처리
    switch (statusCode) {
      case 400:
        // Bad Request - 유효성 검사 실패
        handler.reject(
          DioException(
            requestOptions: err.requestOptions,
            error: ValidationException(
              message: message,
              fieldErrors: _parseFieldErrors(errors),
            ),
            type: err.type,
            response: err.response,
          ),
        );
        break;
        
      case 401:
        // Unauthorized - 인증 실패
        handler.reject(
          DioException(
            requestOptions: err.requestOptions,
            error: UnauthorizedException(
              message: AppConstants.unauthorizedError,
            ),
            type: err.type,
            response: err.response,
          ),
        );
        break;
        
      case 403:
        // Forbidden - 권한 부족
        handler.reject(
          DioException(
            requestOptions: err.requestOptions,
            error: ForbiddenException(
              message: '해당 작업을 수행할 권한이 없습니다.',
            ),
            type: err.type,
            response: err.response,
          ),
        );
        break;
        
      case 404:
        // Not Found - 리소스 없음
        handler.reject(
          DioException(
            requestOptions: err.requestOptions,
            error: NotFoundException(
              message: message,
            ),
            type: err.type,
            response: err.response,
          ),
        );
        break;
        
      case 409:
        // Conflict - 중복 리소스
        handler.reject(
          DioException(
            requestOptions: err.requestOptions,
            error: DuplicateException(
              message: message,
            ),
            type: err.type,
            response: err.response,
          ),
        );
        break;
        
      case 422:
        // Unprocessable Entity - 비즈니스 로직 오류
        handler.reject(
          DioException(
            requestOptions: err.requestOptions,
            error: BusinessException(
              message: message,
              code: data?['code'],
            ),
            type: err.type,
            response: err.response,
          ),
        );
        break;
        
      case 429:
        // Too Many Requests
        handler.reject(
          DioException(
            requestOptions: err.requestOptions,
            error: NetworkException(
              message: '너무 많은 요청을 보냈습니다. 잠시 후 다시 시도해주세요.',
            ),
            type: err.type,
            response: err.response,
          ),
        );
        break;
        
      case 500:
      case 502:
      case 503:
      case 504:
        // Server Error
        handler.reject(
          DioException(
            requestOptions: err.requestOptions,
            error: ServerException(
              message: AppConstants.serverError,
              statusCode: statusCode,
            ),
            type: err.type,
            response: err.response,
          ),
        );
        break;
        
      default:
        handler.reject(
          DioException(
            requestOptions: err.requestOptions,
            error: ServerException(
              message: message,
              statusCode: statusCode,
              errors: errors,
            ),
            type: err.type,
            response: err.response,
          ),
        );
        break;
    }
  }
  
  /// 필드 에러 파싱
  Map<String, List<String>>? _parseFieldErrors(Map<String, dynamic>? errors) {
    if (errors == null) return null;
    
    final fieldErrors = <String, List<String>>{};
    
    errors.forEach((key, value) {
      if (value is List) {
        fieldErrors[key] = value.map((e) => e.toString()).toList();
      } else if (value is String) {
        fieldErrors[key] = [value];
      }
    });
    
    return fieldErrors.isNotEmpty ? fieldErrors : null;
  }
}