import 'package:dio/dio.dart';

/// 에러 타입
enum ErrorType {
  /// 필수 필드 누락
  missingRequiredField,
  
  /// 잘못된 참조
  invalidReference,
  
  /// 중복 데이터
  duplicateData,
  
  /// 권한 부족
  permissionDenied,
  
  /// 유효성 검증 실패
  validation,
  
  /// 서버 에러
  serverError,
  
  /// 네트워크 에러
  networkError,
  
  /// 알 수 없는 에러
  unknown,
}

/// API 에러 타입 분류
enum ApiErrorType {
  /// 인증 관련 에러 (401, 403)
  authentication,
  
  /// 유효성 검증 에러 (400)
  validation,
  
  /// 리소스 찾기 실패 (404)
  notFound,
  
  /// 서버 내부 에러 (500)
  serverError,
  
  /// 네트워크 연결 에러
  networkConnection,
  
  /// 타임아웃 에러
  timeout,
  
  /// 요청 취소
  cancelled,
  
  /// 속도 제한
  rateLimit,
  
  /// 알 수 없는 에러
  unknown,
}

/// API 에러 진단 결과
class ErrorDiagnosis {
  /// API 에러 타입
  final ApiErrorType type;
  
  /// 일반 에러 타입
  final ErrorType errorType;
  
  /// 에러 설명
  final String description;
  
  /// 에러 컨텍스트 정보
  final Map<String, dynamic> context;
  
  /// 진단 신뢰도 (0.0 ~ 1.0)
  final double confidence;
  
  /// 영향받은 API 엔드포인트
  final List<String> affectedEndpoints;
  
  /// 서버 에러 코드 (있는 경우)
  final String? serverErrorCode;
  
  /// 누락된 필드 목록
  final List<String>? missingFields;
  
  /// 타입 불일치 필드 정보
  final Map<String, TypeMismatchInfo>? typeMismatches;
  
  /// 원본 에러 메시지
  final String? originalMessage;
  
  /// 에러 발생 시간
  final DateTime timestamp;

  ErrorDiagnosis({
    required this.type,
    required this.errorType,
    required this.description,
    required this.context,
    required this.confidence,
    required this.affectedEndpoints,
    this.serverErrorCode,
    this.missingFields,
    this.typeMismatches,
    this.originalMessage,
    DateTime? timestamp,
  }) : timestamp = timestamp ?? DateTime.now();
  
  /// JSON으로 변환
  Map<String, dynamic> toJson() {
    return {
      'type': type.toString(),
      'errorType': errorType.toString(),
      'description': description,
      'context': context,
      'confidence': confidence,
      'affectedEndpoints': affectedEndpoints,
      'serverErrorCode': serverErrorCode,
      'missingFields': missingFields,
      'typeMismatches': typeMismatches?.map(
        (key, value) => MapEntry(key, value.toJson()),
      ),
      'originalMessage': originalMessage,
      'timestamp': timestamp.toIso8601String(),
    };
  }
}

/// 타입 불일치 정보
class TypeMismatchInfo {
  /// 필드 이름
  final String fieldName;
  
  /// 예상 타입
  final String expectedType;
  
  /// 실제 타입
  final String actualType;
  
  /// 실제 값
  final dynamic actualValue;

  TypeMismatchInfo({
    required this.fieldName,
    required this.expectedType,
    required this.actualType,
    this.actualValue,
  });
  
  Map<String, dynamic> toJson() {
    return {
      'fieldName': fieldName,
      'expectedType': expectedType,
      'actualType': actualType,
      'actualValue': actualValue,
    };
  }
}

/// 수정 제안 타입
enum FixType {
  /// 토큰 갱신
  refreshToken,
  
  /// 필드 추가
  addMissingField,
  
  /// 타입 변환
  convertType,
  
  /// 재시도
  retry,
  
  /// 데이터 수정
  modifyData,
  
  /// 권한 요청
  requestPermission,
  
  /// 엔드포인트 변경
  endpointSwitch,
  
  /// 설정 변경
  configuration,
  
  /// 수동 개입 필요
  manualIntervention,
}

/// 수정 제안
class FixSuggestion {
  /// 수정 ID
  final String fixId;
  
  /// 수정 타입
  final FixType type;
  
  /// 수정 설명
  final String description;
  
  /// 수정 작업 목록
  final List<FixAction> actions;
  
  /// 성공 확률 (0.0 ~ 1.0)
  final double successProbability;
  
  /// 자동 수정 가능 여부
  final bool isAutoFixable;
  
  /// 예상 소요 시간 (밀리초)
  final int? estimatedDuration;

  FixSuggestion({
    required this.fixId,
    required this.type,
    required this.description,
    required this.actions,
    required this.successProbability,
    required this.isAutoFixable,
    this.estimatedDuration,
  });
  
  Map<String, dynamic> toJson() {
    return {
      'fixId': fixId,
      'type': type.toString(),
      'description': description,
      'actions': actions.map((a) => a.toJson()).toList(),
      'successProbability': successProbability,
      'isAutoFixable': isAutoFixable,
      'estimatedDuration': estimatedDuration,
    };
  }
}

/// 수정 작업
class FixAction {
  /// 작업 타입
  final FixActionType type;
  
  /// 작업 타입 문자열 (하위 호환성)
  final String actionType;
  
  /// 대상
  final String target;
  
  /// 작업 파라미터
  final Map<String, dynamic> parameters;
  
  /// 작업 설명
  final String? description;

  FixAction({
    required this.type,
    required this.actionType,
    required this.target,
    required this.parameters,
    this.description,
  });
  
  Map<String, dynamic> toJson() {
    return {
      'type': type.toString(),
      'actionType': actionType,
      'target': target,
      'parameters': parameters,
      'description': description,
    };
  }
}

/// 수정 결과
class FixResult {
  /// 수정 ID
  final String fixId;
  
  /// 성공 여부
  final bool success;
  
  /// 실행된 작업 목록
  final List<FixAction> executedActions;
  
  /// 실행 시간
  final DateTime executedAt;
  
  /// 소요 시간 (밀리초)
  final int duration;
  
  /// 에러 (실패 시)
  final String? error;
  
  /// 추가 정보
  final Map<String, dynamic>? additionalInfo;

  FixResult({
    required this.fixId,
    required this.success,
    required this.executedActions,
    required this.executedAt,
    required this.duration,
    this.error,
    this.additionalInfo,
  });
  
  Map<String, dynamic> toJson() {
    return {
      'fixId': fixId,
      'success': success,
      'executedActions': executedActions.map((a) => a.toJson()).toList(),
      'executedAt': executedAt.toIso8601String(),
      'duration': duration,
      'error': error,
      'additionalInfo': additionalInfo,
    };
  }
}

/// 자동 수정 결과 (간단한 버전)
class AutoFixResult {
  /// 성공 여부
  final bool success;
  
  /// 수정 ID
  final String fixId;
  
  /// 실행된 액션 목록 (문자열)
  final List<String> executedActions;
  
  /// 소요 시간 (밀리초)
  final int duration;
  
  /// 에러 메시지
  final String? error;
  
  /// 수정된 데이터
  final Map<String, dynamic>? fixedData;

  AutoFixResult({
    required this.success,
    required this.fixId,
    this.executedActions = const [],
    required this.duration,
    this.error,
    this.fixedData,
  });
}

/// 수정 이력 항목
class FixHistoryEntry {
  /// 타임스탬프
  final DateTime timestamp;
  
  /// 수정 결과
  final AutoFixResult fixResult;
  
  /// 액션
  final String action;
  
  /// 컨텍스트
  final Map<String, dynamic>? context;

  FixHistoryEntry({
    required this.timestamp,
    required this.fixResult,
    required this.action,
    this.context,
  });
}

/// 에러 패턴 (학습용)
class ErrorPattern {
  /// 패턴 ID
  final String patternId;
  
  /// 에러 타입
  final ApiErrorType errorType;
  
  /// 패턴 매칭 규칙
  final Map<String, dynamic> matchingRules;
  
  /// 성공한 수정 전략
  final List<FixSuggestion> successfulFixes;
  
  /// 발생 횟수
  final int occurrenceCount;
  
  /// 마지막 발생 시간
  final DateTime lastOccurred;
  
  /// 학습 신뢰도
  final double confidence;

  ErrorPattern({
    required this.patternId,
    required this.errorType,
    required this.matchingRules,
    required this.successfulFixes,
    required this.occurrenceCount,
    required this.lastOccurred,
    required this.confidence,
  });
  
  Map<String, dynamic> toJson() {
    return {
      'patternId': patternId,
      'errorType': errorType.toString(),
      'matchingRules': matchingRules,
      'successfulFixes': successfulFixes.map((f) => f.toJson()).toList(),
      'occurrenceCount': occurrenceCount,
      'lastOccurred': lastOccurred.toIso8601String(),
      'confidence': confidence,
    };
  }
}

/// API 에러 정보
class ApiError {
  /// 원본 에러 (optional)
  final DioException? originalError;
  
  /// 요청 URL
  final String requestUrl;
  
  /// 요청 메서드
  final String requestMethod;
  
  /// 요청 헤더
  final Map<String, dynamic>? requestHeaders;
  
  /// 요청 바디
  final dynamic requestBody;
  
  /// 응답 상태 코드
  final int? statusCode;
  
  /// 응답 바디
  final dynamic responseBody;
  
  /// 에러 메시지
  final String? message;
  
  /// 서버 메시지
  final String? serverMessage;
  
  /// API 엔드포인트
  final String? endpoint;
  
  /// HTTP 메서드
  final String? method;
  
  /// 에러 발생 시간
  final DateTime timestamp;

  ApiError({
    this.originalError,
    required this.requestUrl,
    required this.requestMethod,
    this.requestHeaders,
    this.requestBody,
    this.statusCode,
    this.responseBody,
    this.message,
    this.serverMessage,
    this.endpoint,
    this.method,
    DateTime? timestamp,
  }) : timestamp = timestamp ?? DateTime.now();
  
  /// DioException으로부터 생성
  factory ApiError.fromDioException(DioException error) {
    return ApiError(
      originalError: error,
      requestUrl: error.requestOptions.uri.toString(),
      requestMethod: error.requestOptions.method,
      requestHeaders: error.requestOptions.headers,
      requestBody: error.requestOptions.data,
      statusCode: error.response?.statusCode,
      responseBody: error.response?.data,
      serverMessage: error.response?.data is Map ? error.response?.data['message'] : null,
    );
  }
  
  Map<String, dynamic> toJson() {
    return {
      'requestUrl': requestUrl,
      'requestMethod': requestMethod,
      'requestHeaders': requestHeaders,
      'requestBody': requestBody,
      'statusCode': statusCode,
      'responseBody': responseBody,
      'timestamp': timestamp.toIso8601String(),
      'errorType': originalError?.type.toString(),
      'errorMessage': message ?? originalError?.message,
      'serverMessage': serverMessage,
      'endpoint': endpoint,
      'method': method,
    };
  }
}

/// Fix 액션 타입
enum FixActionType {
  /// 필드 업데이트
  updateField,
  
  /// 누락된 리소스 생성
  createMissingResource,
  
  /// 재시도 with 지연
  retryWithDelay,
  
  /// 데이터 타입 변환
  convertDataType,
  
  /// 권한 변경
  changePermission,
  
  /// 알수 없음
  unknown,
}

/// 근본 원인 분석 결과
class RootCause {
  /// 원인 타입
  final String causeType;
  
  /// 원인 설명
  final String description;
  
  /// 증거 목록
  final List<String> evidence;
  
  /// 연관된 진단 결과
  final ErrorDiagnosis diagnosis;
  
  /// 권장 수정 방법
  final List<FixSuggestion> recommendedFixes;

  RootCause({
    required this.causeType,
    required this.description,
    required this.evidence,
    required this.diagnosis,
    required this.recommendedFixes,
  });
  
  Map<String, dynamic> toJson() {
    return {
      'causeType': causeType,
      'description': description,
      'evidence': evidence,
      'diagnosis': diagnosis.toJson(),
      'recommendedFixes': recommendedFixes.map((f) => f.toJson()).toList(),
    };
  }
}

/// 변경 사항
class Change {
  /// 변경 타입
  final String type;
  
  /// 변경 전 값
  final dynamic before;
  
  /// 변경 후 값
  final dynamic after;
  
  /// 변경 대상
  final String target;

  Change({
    required this.type,
    this.before,
    this.after,
    required this.target,
  });
  
  Map<String, dynamic> toJson() {
    return {
      'type': type,
      'before': before,
      'after': after,
      'target': target,
    };
  }
}