import 'package:dio/dio.dart';
import '../models/error_models.dart';

/// API 에러 진단 시스템
class ApiErrorDiagnostics {
  /// 학습된 에러 패턴
  final Map<String, ErrorPattern> _learnedPatterns = {};
  
  /// 진단 규칙 목록
  final List<DiagnosticRule> _diagnosticRules = [];
  
  /// 기본 생성자
  ApiErrorDiagnostics() {
    _initializeDefaultRules();
  }
  
  /// 기본 진단 규칙 초기화
  void _initializeDefaultRules() {
    _diagnosticRules.addAll([
      AuthenticationDiagnosticRule(),
      ValidationDiagnosticRule(),
      NetworkDiagnosticRule(),
      ServerErrorDiagnosticRule(),
      NotFoundDiagnosticRule(),
      RateLimitDiagnosticRule(),
    ]);
  }
  
  /// API 에러 진단
  Future<ErrorDiagnosis> diagnose(ApiError error) async {
    // 1. 학습된 패턴에서 먼저 매칭 시도
    final matchedPattern = _findMatchingPattern(error);
    if (matchedPattern != null) {
      return _createDiagnosisFromPattern(error, matchedPattern);
    }
    
    // 2. 진단 규칙 순회
    for (final rule in _diagnosticRules) {
      if (rule.canHandle(error)) {
        return await rule.diagnose(error);
      }
    }
    
    // 3. 기본 진단 반환
    return _createDefaultDiagnosis(error);
  }
  
  /// 근본 원인 분석
  Future<RootCause> analyzeRootCause(ErrorDiagnosis diagnosis) async {
    final causeType = _determineCauseType(diagnosis);
    final evidence = await _collectEvidence(diagnosis);
    final description = _generateCauseDescription(diagnosis, evidence);
    final fixes = await suggestFixes(diagnosis);
    
    return RootCause(
      causeType: causeType,
      description: description,
      evidence: evidence,
      diagnosis: diagnosis,
      recommendedFixes: fixes,
    );
  }
  
  /// 수정 제안
  Future<List<FixSuggestion>> suggestFixes(ErrorDiagnosis diagnosis) async {
    final suggestions = <FixSuggestion>[];
    
    switch (diagnosis.type) {
      case ApiErrorType.authentication:
        suggestions.addAll(_createAuthenticationFixes(diagnosis));
        break;
      case ApiErrorType.validation:
        suggestions.addAll(_createValidationFixes(diagnosis));
        break;
      case ApiErrorType.networkConnection:
        suggestions.addAll(_createNetworkFixes(diagnosis));
        break;
      case ApiErrorType.serverError:
        suggestions.addAll(_createServerErrorFixes(diagnosis));
        break;
      case ApiErrorType.notFound:
        suggestions.addAll(_createNotFoundFixes(diagnosis));
        break;
      case ApiErrorType.rateLimit:
        suggestions.addAll(_createRateLimitFixes(diagnosis));
        break;
      default:
        suggestions.add(_createGenericRetryFix());
    }
    
    return suggestions;
  }
  
  /// 에러로부터 학습
  Future<void> learnFromError(ApiError error, FixResult fixResult) async {
    if (!fixResult.success) return;
    
    final diagnosis = await diagnose(error);
    final patternId = _generatePatternId(error);
    
    final existingPattern = _learnedPatterns[patternId];
    if (existingPattern != null) {
      // 기존 패턴 업데이트
      _updatePattern(existingPattern, fixResult);
    } else {
      // 새로운 패턴 생성
      _createNewPattern(error, diagnosis, fixResult);
    }
  }
  
  /// 학습된 패턴 찾기
  ErrorPattern? _findMatchingPattern(ApiError error) {
    for (final pattern in _learnedPatterns.values) {
      if (_matchesPattern(error, pattern)) {
        return pattern;
      }
    }
    return null;
  }
  
  /// 패턴 매칭 확인
  bool _matchesPattern(ApiError error, ErrorPattern pattern) {
    final rules = pattern.matchingRules;
    
    // 상태 코드 매칭
    if (rules['statusCode'] != null && rules['statusCode'] != error.statusCode) {
      return false;
    }
    
    // 에러 타입 매칭
    if (rules['errorType'] != null && 
        rules['errorType'] != error.originalError?.type.toString()) {
      return false;
    }
    
    // URL 패턴 매칭
    if (rules['urlPattern'] != null) {
      final pattern = RegExp(rules['urlPattern'] as String);
      if (!pattern.hasMatch(error.requestUrl)) {
        return false;
      }
    }
    
    // 에러 메시지 패턴 매칭
    if (rules['messagePattern'] != null && error.responseBody != null) {
      final pattern = RegExp(rules['messagePattern'] as String);
      final message = error.responseBody.toString();
      if (!pattern.hasMatch(message)) {
        return false;
      }
    }
    
    return true;
  }
  
  /// 패턴으로부터 진단 생성
  ErrorDiagnosis _createDiagnosisFromPattern(ApiError error, ErrorPattern pattern) {
    return ErrorDiagnosis(
      type: pattern.errorType,
      errorType: _mapApiErrorToErrorType(pattern.errorType),
      description: '학습된 패턴과 일치하는 에러입니다.',
      context: {
        'patternId': pattern.patternId,
        'confidence': pattern.confidence,
        'occurrenceCount': pattern.occurrenceCount,
      },
      confidence: pattern.confidence,
      affectedEndpoints: [error.requestUrl],
      originalMessage: error.originalError?.message,
    );
  }
  
  /// 기본 진단 생성
  ErrorDiagnosis _createDefaultDiagnosis(ApiError error) {
    return ErrorDiagnosis(
      type: ApiErrorType.unknown,
      errorType: ErrorType.unknown,
      description: '알 수 없는 에러가 발생했습니다.',
      context: {
        'statusCode': error.statusCode,
        'errorType': error.originalError?.type.toString() ?? 'unknown',
      },
      confidence: 0.3,
      affectedEndpoints: [error.requestUrl],
      originalMessage: error.originalError?.message,
    );
  }
  
  /// 원인 타입 결정
  String _determineCauseType(ErrorDiagnosis diagnosis) {
    switch (diagnosis.type) {
      case ApiErrorType.authentication:
        return 'authentication_failure';
      case ApiErrorType.validation:
        return 'data_validation_error';
      case ApiErrorType.networkConnection:
        return 'network_connectivity';
      case ApiErrorType.serverError:
        return 'server_side_error';
      case ApiErrorType.notFound:
        return 'resource_not_found';
      case ApiErrorType.rateLimit:
        return 'rate_limit_exceeded';
      default:
        return 'unknown_error';
    }
  }
  
  /// 증거 수집
  Future<List<String>> _collectEvidence(ErrorDiagnosis diagnosis) async {
    final evidence = <String>[];
    
    // 기본 정보
    evidence.add('에러 타입: ${diagnosis.type}');
    evidence.add('발생 시간: ${diagnosis.timestamp.toIso8601String()}');
    
    // 서버 에러 코드
    if (diagnosis.serverErrorCode != null) {
      evidence.add('서버 에러 코드: ${diagnosis.serverErrorCode}');
    }
    
    // 누락된 필드
    if (diagnosis.missingFields != null && diagnosis.missingFields!.isNotEmpty) {
      evidence.add('누락된 필드: ${diagnosis.missingFields!.join(', ')}');
    }
    
    // 타입 불일치
    if (diagnosis.typeMismatches != null && diagnosis.typeMismatches!.isNotEmpty) {
      for (final mismatch in diagnosis.typeMismatches!.values) {
        evidence.add('타입 불일치 - ${mismatch.fieldName}: '
            '예상 ${mismatch.expectedType}, 실제 ${mismatch.actualType}');
      }
    }
    
    return evidence;
  }
  
  /// 원인 설명 생성
  String _generateCauseDescription(ErrorDiagnosis diagnosis, List<String> evidence) {
    final buffer = StringBuffer();
    
    switch (diagnosis.type) {
      case ApiErrorType.authentication:
        buffer.write('인증 실패: 토큰이 만료되었거나 유효하지 않습니다.');
        break;
      case ApiErrorType.validation:
        buffer.write('데이터 유효성 검증 실패: ');
        if (diagnosis.missingFields != null && diagnosis.missingFields!.isNotEmpty) {
          buffer.write('필수 필드가 누락되었습니다.');
        } else if (diagnosis.typeMismatches != null && diagnosis.typeMismatches!.isNotEmpty) {
          buffer.write('데이터 타입이 일치하지 않습니다.');
        } else {
          buffer.write('입력 데이터가 서버 요구사항을 충족하지 않습니다.');
        }
        break;
      case ApiErrorType.networkConnection:
        buffer.write('네트워크 연결 실패: 인터넷 연결을 확인하거나 서버 상태를 확인하세요.');
        break;
      case ApiErrorType.serverError:
        buffer.write('서버 내부 오류: 서버에서 예상치 못한 오류가 발생했습니다.');
        break;
      case ApiErrorType.notFound:
        buffer.write('리소스를 찾을 수 없음: 요청한 리소스가 존재하지 않거나 접근 권한이 없습니다.');
        break;
      case ApiErrorType.rateLimit:
        buffer.write('요청 제한 초과: API 호출 제한을 초과했습니다.');
        break;
      default:
        buffer.write('알 수 없는 오류가 발생했습니다.');
    }
    
    return buffer.toString();
  }
  
  /// 인증 관련 수정 제안 생성
  List<FixSuggestion> _createAuthenticationFixes(ErrorDiagnosis diagnosis) {
    return [
      FixSuggestion(
        fixId: 'auth_refresh_token',
        type: FixType.refreshToken,
        description: '토큰을 갱신하여 인증 문제를 해결합니다.',
        actions: [
          FixAction(
            type: FixActionType.changePermission,
            actionType: 'refresh_token',
            target: 'auth_service',
            parameters: {},
            description: '리프레시 토큰을 사용하여 액세스 토큰 갱신',
          ),
        ],
        successProbability: 0.85,
        isAutoFixable: true,
        estimatedDuration: 500,
      ),
      FixSuggestion(
        fixId: 'auth_relogin',
        type: FixType.manualIntervention,
        description: '다시 로그인하여 새로운 인증 정보를 획득합니다.',
        actions: [
          FixAction(
            type: FixActionType.changePermission,
            actionType: 'navigate',
            target: 'login_screen',
            parameters: {'reason': 'token_expired'},
            description: '로그인 화면으로 이동',
          ),
        ],
        successProbability: 0.95,
        isAutoFixable: false,
      ),
    ];
  }
  
  /// 유효성 검증 관련 수정 제안 생성
  List<FixSuggestion> _createValidationFixes(ErrorDiagnosis diagnosis) {
    final fixes = <FixSuggestion>[];
    
    // 누락된 필드 추가
    if (diagnosis.missingFields != null && diagnosis.missingFields!.isNotEmpty) {
      fixes.add(FixSuggestion(
        fixId: 'validation_add_fields',
        type: FixType.addMissingField,
        description: '누락된 필수 필드를 추가합니다.',
        actions: diagnosis.missingFields!.map((field) => FixAction(
          type: FixActionType.updateField,
          actionType: 'add_field',
          target: 'request_body',
          parameters: {
            'field': field,
            'defaultValue': _getDefaultValueForField(field),
          },
          description: '$field 필드 추가',
        )).toList(),
        successProbability: 0.8,
        isAutoFixable: true,
        estimatedDuration: 100,
      ));
    }
    
    // 타입 불일치 수정
    if (diagnosis.typeMismatches != null && diagnosis.typeMismatches!.isNotEmpty) {
      fixes.add(FixSuggestion(
        fixId: 'validation_convert_types',
        type: FixType.convertType,
        description: '잘못된 데이터 타입을 변환합니다.',
        actions: diagnosis.typeMismatches!.values.map((mismatch) => FixAction(
          type: FixActionType.convertDataType,
          actionType: 'convert_type',
          target: 'request_body',
          parameters: {
            'field': mismatch.fieldName,
            'fromType': mismatch.actualType,
            'toType': mismatch.expectedType,
            'value': mismatch.actualValue,
          },
          description: '${mismatch.fieldName} 타입 변환',
        )).toList(),
        successProbability: 0.75,
        isAutoFixable: true,
        estimatedDuration: 150,
      ));
    }
    
    return fixes;
  }
  
  /// 네트워크 관련 수정 제안 생성
  List<FixSuggestion> _createNetworkFixes(ErrorDiagnosis diagnosis) {
    return [
      FixSuggestion(
        fixId: 'network_retry',
        type: FixType.retry,
        description: '네트워크 요청을 재시도합니다.',
        actions: [
          FixAction(
            type: FixActionType.retryWithDelay,
            actionType: 'retry_request',
            target: 'api_client',
            parameters: {
              'maxAttempts': 3,
              'backoffDelay': 1000,
            },
            description: '지수 백오프로 재시도',
          ),
        ],
        successProbability: 0.7,
        isAutoFixable: true,
        estimatedDuration: 3000,
      ),
      FixSuggestion(
        fixId: 'network_check_connection',
        type: FixType.configuration,
        description: '네트워크 연결 상태를 확인하고 재연결을 시도합니다.',
        actions: [
          FixAction(
            type: FixActionType.retryWithDelay,
            actionType: 'check_connectivity',
            target: 'network_manager',
            parameters: {},
            description: '네트워크 연결 확인',
          ),
          FixAction(
            type: FixActionType.retryWithDelay,
            actionType: 'reset_connection',
            target: 'api_client',
            parameters: {},
            description: '연결 재설정',
          ),
        ],
        successProbability: 0.6,
        isAutoFixable: true,
        estimatedDuration: 2000,
      ),
    ];
  }
  
  /// 서버 에러 관련 수정 제안 생성
  List<FixSuggestion> _createServerErrorFixes(ErrorDiagnosis diagnosis) {
    return [
      FixSuggestion(
        fixId: 'server_retry_later',
        type: FixType.retry,
        description: '잠시 후 다시 시도합니다.',
        actions: [
          FixAction(
            type: FixActionType.retryWithDelay,
            actionType: 'delayed_retry',
            target: 'api_client',
            parameters: {
              'delay': 5000,
              'maxAttempts': 2,
            },
            description: '5초 후 재시도',
          ),
        ],
        successProbability: 0.5,
        isAutoFixable: true,
        estimatedDuration: 5000,
      ),
      FixSuggestion(
        fixId: 'server_fallback',
        type: FixType.endpointSwitch,
        description: '대체 엔드포인트로 전환합니다.',
        actions: [
          FixAction(
            type: FixActionType.retryWithDelay,
            actionType: 'switch_endpoint',
            target: 'api_client',
            parameters: {
              'useFallback': true,
            },
            description: '백업 서버로 전환',
          ),
        ],
        successProbability: 0.7,
        isAutoFixable: true,
        estimatedDuration: 1000,
      ),
    ];
  }
  
  /// Not Found 관련 수정 제안 생성
  List<FixSuggestion> _createNotFoundFixes(ErrorDiagnosis diagnosis) {
    return [
      FixSuggestion(
        fixId: 'notfound_verify_id',
        type: FixType.modifyData,
        description: '리소스 ID를 확인하고 수정합니다.',
        actions: [
          FixAction(
            type: FixActionType.updateField,
            actionType: 'verify_resource_id',
            target: 'request_params',
            parameters: {},
            description: '리소스 ID 유효성 확인',
          ),
        ],
        successProbability: 0.4,
        isAutoFixable: false,
        estimatedDuration: 100,
      ),
      FixSuggestion(
        fixId: 'notfound_refresh_list',
        type: FixType.retry,
        description: '리소스 목록을 새로고침합니다.',
        actions: [
          FixAction(
            type: FixActionType.retryWithDelay,
            actionType: 'refresh_resource_list',
            target: 'resource_cache',
            parameters: {},
            description: '캐시된 리소스 목록 갱신',
          ),
        ],
        successProbability: 0.6,
        isAutoFixable: true,
        estimatedDuration: 2000,
      ),
    ];
  }
  
  /// Rate Limit 관련 수정 제안 생성
  List<FixSuggestion> _createRateLimitFixes(ErrorDiagnosis diagnosis) {
    return [
      FixSuggestion(
        fixId: 'ratelimit_wait',
        type: FixType.retry,
        description: '제한이 해제될 때까지 대기 후 재시도합니다.',
        actions: [
          FixAction(
            type: FixActionType.retryWithDelay,
            actionType: 'wait_and_retry',
            target: 'api_client',
            parameters: {
              'waitTime': 60000, // 1분
            },
            description: '1분 대기 후 재시도',
          ),
        ],
        successProbability: 0.9,
        isAutoFixable: true,
        estimatedDuration: 60000,
      ),
      FixSuggestion(
        fixId: 'ratelimit_reduce_frequency',
        type: FixType.configuration,
        description: 'API 호출 빈도를 줄입니다.',
        actions: [
          FixAction(
            type: FixActionType.retryWithDelay,
            actionType: 'configure_throttling',
            target: 'api_client',
            parameters: {
              'maxRequestsPerMinute': 30,
            },
            description: 'API 호출 제한 설정',
          ),
        ],
        successProbability: 0.85,
        isAutoFixable: true,
        estimatedDuration: 100,
      ),
    ];
  }
  
  /// 일반적인 재시도 수정 제안 생성
  FixSuggestion _createGenericRetryFix() {
    return FixSuggestion(
      fixId: 'generic_retry',
      type: FixType.retry,
      description: '요청을 재시도합니다.',
      actions: [
        FixAction(
          type: FixActionType.retryWithDelay,
          actionType: 'retry_request',
          target: 'api_client',
          parameters: {
            'maxAttempts': 2,
          },
          description: '기본 재시도',
        ),
      ],
      successProbability: 0.3,
      isAutoFixable: true,
      estimatedDuration: 1000,
    );
  }
  
  /// 필드의 기본값 반환
  dynamic _getDefaultValueForField(String field) {
    // 필드 이름에 따른 기본값 매핑
    final defaultValues = {
      'name': '미지정',
      'description': '',
      'quantity': 1,
      'price': 0,
      'is_active': true,
      'created_at': DateTime.now().toIso8601String(),
      'updated_at': DateTime.now().toIso8601String(),
    };
    
    // 특정 패턴에 따른 기본값
    if (field.endsWith('_id')) return 0;
    if (field.endsWith('_date')) return DateTime.now().toIso8601String();
    if (field.endsWith('_count')) return 0;
    if (field.startsWith('is_')) return false;
    if (field.startsWith('has_')) return false;
    
    return defaultValues[field] ?? '';
  }
  
  /// 패턴 ID 생성
  String _generatePatternId(ApiError error) {
    final components = [
      error.statusCode?.toString() ?? 'unknown',
      error.requestMethod,
      Uri.parse(error.requestUrl).path,
      error.originalError?.type.toString() ?? 'unknown',
    ];
    
    return components.join('_').replaceAll('/', '_');
  }
  
  /// 패턴 업데이트
  void _updatePattern(ErrorPattern pattern, FixResult fixResult) {
    // 성공한 수정 전략 추가 (중복 제거)
    final fixIds = pattern.successfulFixes.map((f) => f.fixId).toSet();
    for (final action in fixResult.executedActions) {
      if (!fixIds.contains(action.actionType)) {
        // 새로운 수정 전략 추가는 실제 FixSuggestion 객체가 필요하므로 생략
      }
    }
    
    // 발생 횟수 및 신뢰도 업데이트
    final updatedPattern = ErrorPattern(
      patternId: pattern.patternId,
      errorType: pattern.errorType,
      matchingRules: pattern.matchingRules,
      successfulFixes: pattern.successfulFixes,
      occurrenceCount: pattern.occurrenceCount + 1,
      lastOccurred: DateTime.now(),
      confidence: _calculateUpdatedConfidence(pattern.confidence, pattern.occurrenceCount),
    );
    
    _learnedPatterns[pattern.patternId] = updatedPattern;
  }
  
  /// 새로운 패턴 생성
  void _createNewPattern(ApiError error, ErrorDiagnosis diagnosis, FixResult fixResult) {
    final patternId = _generatePatternId(error);
    
    final pattern = ErrorPattern(
      patternId: patternId,
      errorType: diagnosis.type,
      matchingRules: {
        'statusCode': error.statusCode,
        'errorType': error.originalError?.type.toString() ?? 'unknown',
        'urlPattern': Uri.parse(error.requestUrl).path,
        if (error.responseBody != null && error.responseBody is Map)
          'messagePattern': _extractMessagePattern(error.responseBody),
      },
      successfulFixes: [], // 실제 구현에서는 fixResult로부터 생성
      occurrenceCount: 1,
      lastOccurred: DateTime.now(),
      confidence: 0.5,
    );
    
    _learnedPatterns[patternId] = pattern;
  }
  
  /// 메시지 패턴 추출
  String? _extractMessagePattern(dynamic responseBody) {
    if (responseBody is Map) {
      // 서버 에러 형식에 따른 메시지 추출
      if (responseBody['error'] != null && responseBody['error'] is Map) {
        final errorCode = responseBody['error']['code'];
        if (errorCode != null) {
          return errorCode.toString();
        }
      }
      
      if (responseBody['message'] != null) {
        // 메시지에서 일반적인 패턴 추출
        final message = responseBody['message'].toString();
        if (message.contains('필수 필드')) {
          return 'VALIDATION_ERROR';
        }
      }
    }
    
    return null;
  }
  
  /// 업데이트된 신뢰도 계산
  double _calculateUpdatedConfidence(double currentConfidence, int occurrenceCount) {
    // 발생 횟수에 따라 신뢰도 증가
    final increment = 0.05 * (1.0 - currentConfidence);
    return (currentConfidence + increment).clamp(0.0, 0.95);
  }
  
  /// ApiErrorType을 ErrorType으로 매핑
  ErrorType _mapApiErrorToErrorType(ApiErrorType apiErrorType) {
    switch (apiErrorType) {
      case ApiErrorType.authentication:
        return ErrorType.permissionDenied;
      case ApiErrorType.validation:
        return ErrorType.validation;
      case ApiErrorType.notFound:
        return ErrorType.invalidReference;
      case ApiErrorType.serverError:
        return ErrorType.serverError;
      case ApiErrorType.networkConnection:
      case ApiErrorType.timeout:
        return ErrorType.networkError;
      case ApiErrorType.rateLimit:
      case ApiErrorType.unknown:
      default:
        return ErrorType.unknown;
    }
  }
}

/// 진단 규칙 인터페이스
abstract class DiagnosticRule {
  bool canHandle(ApiError error);
  Future<ErrorDiagnosis> diagnose(ApiError error);
}

/// 인증 진단 규칙
class AuthenticationDiagnosticRule implements DiagnosticRule {
  @override
  bool canHandle(ApiError error) {
    return error.statusCode == 401 || error.statusCode == 403;
  }
  
  @override
  Future<ErrorDiagnosis> diagnose(ApiError error) async {
    return ErrorDiagnosis(
      type: ApiErrorType.authentication,
      errorType: error.statusCode == 403 ? ErrorType.permissionDenied : ErrorType.unknown,
      description: '인증 실패: ${error.statusCode == 401 ? '인증 정보가 없거나 만료되었습니다' : '접근 권한이 없습니다'}',
      context: {
        'statusCode': error.statusCode,
        'endpoint': error.requestUrl,
        'method': error.requestMethod,
      },
      confidence: 0.95,
      affectedEndpoints: [error.requestUrl],
      serverErrorCode: _extractServerErrorCode(error.responseBody),
      originalMessage: error.originalError?.message,
    );
  }
  
  String? _extractServerErrorCode(dynamic responseBody) {
    if (responseBody is Map) {
      if (responseBody['error'] is Map) {
        return responseBody['error']['code']?.toString();
      }
      return responseBody['code']?.toString();
    }
    return null;
  }
}

/// 유효성 검증 진단 규칙
class ValidationDiagnosticRule implements DiagnosticRule {
  @override
  bool canHandle(ApiError error) {
    return error.statusCode == 400 || error.statusCode == 422;
  }
  
  @override
  Future<ErrorDiagnosis> diagnose(ApiError error) async {
    final missingFields = _extractMissingFields(error.responseBody);
    final typeMismatches = _extractTypeMismatches(error.responseBody);
    
    return ErrorDiagnosis(
      type: ApiErrorType.validation,
      errorType: ErrorType.validation,
      description: '데이터 유효성 검증 실패',
      context: {
        'statusCode': error.statusCode,
        'endpoint': error.requestUrl,
        'method': error.requestMethod,
        'requestBody': error.requestBody,
      },
      confidence: 0.9,
      affectedEndpoints: [error.requestUrl],
      serverErrorCode: _extractServerErrorCode(error.responseBody),
      missingFields: missingFields,
      typeMismatches: typeMismatches,
      originalMessage: error.originalError?.message,
    );
  }
  
  List<String>? _extractMissingFields(dynamic responseBody) {
    if (responseBody is Map) {
      final error = responseBody['error'];
      if (error is Map && error['message'] != null) {
        final message = error['message'].toString();
        
        // "필수 필드가 누락되었습니다: field1, field2" 형식 파싱
        if (message.contains('필수 필드가 누락되었습니다:')) {
          final fieldsStr = message.split(':').last.trim();
          return fieldsStr.split(',').map((f) => f.trim()).toList();
        }
      }
      
      // validation_errors 필드 확인
      if (responseBody['validation_errors'] is Map) {
        final errors = responseBody['validation_errors'] as Map;
        return errors.keys.map((k) => k.toString()).toList();
      }
    }
    
    return null;
  }
  
  Map<String, TypeMismatchInfo>? _extractTypeMismatches(dynamic responseBody) {
    // 실제 서버 응답에 따라 구현
    // 예시로 빈 맵 반환
    return null;
  }
  
  String? _extractServerErrorCode(dynamic responseBody) {
    if (responseBody is Map) {
      if (responseBody['error'] is Map) {
        return responseBody['error']['code']?.toString();
      }
      return responseBody['code']?.toString();
    }
    return null;
  }
}

/// 네트워크 진단 규칙
class NetworkDiagnosticRule implements DiagnosticRule {
  @override
  bool canHandle(ApiError error) {
    return error.originalError?.type == DioExceptionType.connectionTimeout ||
        error.originalError?.type == DioExceptionType.sendTimeout ||
        error.originalError?.type == DioExceptionType.receiveTimeout ||
        error.originalError?.type == DioExceptionType.connectionError;
  }
  
  @override
  Future<ErrorDiagnosis> diagnose(ApiError error) async {
    final errorType = error.originalError?.type;
    String description;
    
    switch (errorType) {
      case DioExceptionType.connectionTimeout:
        description = '연결 시간 초과: 서버에 연결할 수 없습니다';
        break;
      case DioExceptionType.sendTimeout:
        description = '전송 시간 초과: 요청을 전송하는 중 시간이 초과되었습니다';
        break;
      case DioExceptionType.receiveTimeout:
        description = '수신 시간 초과: 응답을 받는 중 시간이 초과되었습니다';
        break;
      case DioExceptionType.connectionError:
        description = '연결 오류: 네트워크에 연결할 수 없습니다';
        break;
      default:
        description = '네트워크 오류가 발생했습니다';
    }
    
    return ErrorDiagnosis(
      type: errorType == DioExceptionType.connectionError 
          ? ApiErrorType.networkConnection 
          : ApiErrorType.timeout,
      errorType: ErrorType.networkError,
      description: description,
      context: {
        'errorType': errorType.toString(),
        'endpoint': error.requestUrl,
        'method': error.requestMethod,
      },
      confidence: 0.85,
      affectedEndpoints: [error.requestUrl],
      originalMessage: error.originalError?.message,
    );
  }
}

/// 서버 에러 진단 규칙
class ServerErrorDiagnosticRule implements DiagnosticRule {
  @override
  bool canHandle(ApiError error) {
    final statusCode = error.statusCode ?? 0;
    return statusCode >= 500 && statusCode < 600;
  }
  
  @override
  Future<ErrorDiagnosis> diagnose(ApiError error) async {
    return ErrorDiagnosis(
      type: ApiErrorType.serverError,
      errorType: ErrorType.serverError,
      description: '서버 내부 오류: 서버에서 요청을 처리하는 중 오류가 발생했습니다',
      context: {
        'statusCode': error.statusCode,
        'endpoint': error.requestUrl,
        'method': error.requestMethod,
        'serverMessage': _extractServerMessage(error.responseBody),
      },
      confidence: 0.8,
      affectedEndpoints: [error.requestUrl],
      serverErrorCode: _extractServerErrorCode(error.responseBody),
      originalMessage: error.originalError?.message,
    );
  }
  
  String? _extractServerMessage(dynamic responseBody) {
    if (responseBody is Map) {
      return responseBody['message']?.toString() ?? 
             responseBody['error']?.toString();
    }
    return null;
  }
  
  String? _extractServerErrorCode(dynamic responseBody) {
    if (responseBody is Map) {
      if (responseBody['error'] is Map) {
        return responseBody['error']['code']?.toString();
      }
      return responseBody['code']?.toString();
    }
    return null;
  }
}

/// Not Found 진단 규칙
class NotFoundDiagnosticRule implements DiagnosticRule {
  @override
  bool canHandle(ApiError error) {
    return error.statusCode == 404;
  }
  
  @override
  Future<ErrorDiagnosis> diagnose(ApiError error) async {
    return ErrorDiagnosis(
      type: ApiErrorType.notFound,
      errorType: ErrorType.unknown,
      description: '리소스를 찾을 수 없음: 요청한 리소스가 존재하지 않습니다',
      context: {
        'statusCode': error.statusCode,
        'endpoint': error.requestUrl,
        'method': error.requestMethod,
        'resourceId': _extractResourceId(error.requestUrl),
      },
      confidence: 0.95,
      affectedEndpoints: [error.requestUrl],
      originalMessage: error.originalError?.message,
    );
  }
  
  String? _extractResourceId(String url) {
    final uri = Uri.parse(url);
    final segments = uri.pathSegments;
    
    // URL의 마지막 세그먼트가 숫자인 경우 ID로 간주
    if (segments.isNotEmpty) {
      final lastSegment = segments.last;
      if (int.tryParse(lastSegment) != null) {
        return lastSegment;
      }
    }
    
    return null;
  }
}

/// Rate Limit 진단 규칙
class RateLimitDiagnosticRule implements DiagnosticRule {
  @override
  bool canHandle(ApiError error) {
    return error.statusCode == 429;
  }
  
  @override
  Future<ErrorDiagnosis> diagnose(ApiError error) async {
    final retryAfter = _extractRetryAfter(error.originalError?.response?.headers);
    
    return ErrorDiagnosis(
      type: ApiErrorType.rateLimit,
      errorType: ErrorType.unknown,
      description: '요청 제한 초과: API 호출 제한을 초과했습니다',
      context: {
        'statusCode': error.statusCode,
        'endpoint': error.requestUrl,
        'method': error.requestMethod,
        'retryAfter': retryAfter,
      },
      confidence: 0.95,
      affectedEndpoints: [error.requestUrl],
      originalMessage: error.originalError?.message,
    );
  }
  
  int? _extractRetryAfter(Headers? headers) {
    if (headers == null) return null;
    
    final retryAfter = headers.value('retry-after');
    if (retryAfter != null) {
      return int.tryParse(retryAfter);
    }
    
    return null;
  }
}