import 'dart:async';
import '../models/error_models.dart';
import 'api_error_diagnostics.dart';

/// API 자동 수정 시스템
class ApiAutoFixer {
  final ApiErrorDiagnostics diagnostics;
  final List<FixHistoryEntry> _fixHistory = [];
  final Map<String, int> _fixAttempts = {};
  final Map<String, int> _successfulFixes = {};
  
  /// 생성자
  ApiAutoFixer({required this.diagnostics});

  /// 자동 수정 시도
  Future<AutoFixResult> attemptAutoFix(ErrorDiagnosis diagnosis) async {
    final stopwatch = Stopwatch()..start();
    final fixId = 'fix_${DateTime.now().millisecondsSinceEpoch}';
    
    try {
      // 수정 제안 가져오기
      final suggestions = await diagnostics.suggestFixes(diagnosis);
      
      // 자동 수정 가능한 제안 필터링
      final autoFixableSuggestions = suggestions
          .where((s) => s.isAutoFixable)
          .toList()
        ..sort((a, b) => b.successProbability.compareTo(a.successProbability));
      
      if (autoFixableSuggestions.isEmpty) {
        return AutoFixResult(
          success: false,
          fixId: fixId,
          duration: stopwatch.elapsed.inMilliseconds,
          error: '자동 수정 가능한 방법이 없습니다',
        );
      }
      
      // 가장 높은 성공 확률을 가진 수정 방법 선택
      final selectedFix = autoFixableSuggestions.first;
      
      // 수정 시도 카운트 증가
      _fixAttempts[selectedFix.type.toString()] = 
          (_fixAttempts[selectedFix.type.toString()] ?? 0) + 1;
      
      // 수정 실행
      final executedActions = <String>[];
      final fixedData = <String, dynamic>{};
      
      for (final action in selectedFix.actions) {
        final actionResult = await _executeAction(action, diagnosis);
        if (actionResult['success'] == true) {
          executedActions.add(action.description ?? action.actionType);
          if (actionResult['data'] != null) {
            fixedData.addAll(actionResult['data'] as Map<String, dynamic>);
          }
        } else {
          return AutoFixResult(
            success: false,
            fixId: fixId,
            executedActions: executedActions,
            duration: stopwatch.elapsed.inMilliseconds,
            error: actionResult['error']?.toString() ?? '액션 실행 실패',
            fixedData: fixedData.isEmpty ? null : fixedData,
          );
        }
      }
      
      // 성공 카운트 증가
      _successfulFixes[selectedFix.type.toString()] = 
          (_successfulFixes[selectedFix.type.toString()] ?? 0) + 1;
      
      // 수정 결과 생성
      final result = AutoFixResult(
        success: true,
        fixId: fixId,
        executedActions: executedActions,
        duration: stopwatch.elapsed.inMilliseconds,
        fixedData: fixedData.isEmpty ? null : fixedData,
      );
      
      // 이력에 추가
      _fixHistory.add(FixHistoryEntry(
        timestamp: DateTime.now(),
        fixResult: result,
        action: selectedFix.description,
        context: {
          'fixType': selectedFix.type.toString(),
          'successProbability': selectedFix.successProbability,
        },
      ));
      
      return result;
      
    } catch (e) {
      return AutoFixResult(
        success: false,
        fixId: fixId,
        duration: stopwatch.elapsed.inMilliseconds,
        error: '자동 수정 중 오류 발생: $e',
      );
    }
  }

  /// 액션 실행
  Future<Map<String, dynamic>> _executeAction(
    FixAction action,
    ErrorDiagnosis diagnosis,
  ) async {
    try {
      switch (action.type) {
        case FixActionType.updateField:
          return await _executeUpdateField(action, diagnosis);
        
        case FixActionType.createMissingResource:
          return await _executeCreateResource(action, diagnosis);
        
        case FixActionType.retryWithDelay:
          return await _executeRetryWithDelay(action, diagnosis);
        
        case FixActionType.convertDataType:
          return await _executeConvertDataType(action, diagnosis);
        
        case FixActionType.changePermission:
          return await _executeChangePermission(action, diagnosis);
        
        case FixActionType.unknown:
        default:
          return {'success': false, 'error': '알 수 없는 액션 타입'};
      }
    } catch (e) {
      return {'success': false, 'error': e.toString()};
    }
  }

  /// 필드 업데이트 실행
  Future<Map<String, dynamic>> _executeUpdateField(
    FixAction action,
    ErrorDiagnosis diagnosis,
  ) async {
    final field = action.parameters['field'] as String?;
    final defaultValue = action.parameters['defaultValue'];
    
    if (field == null) {
      return {'success': false, 'error': '필드명이 지정되지 않았습니다'};
    }
    
    // 실제 구현에서는 요청 데이터를 수정하는 로직이 들어갑니다
    return {
      'success': true,
      'data': {field: defaultValue},
    };
  }

  /// 리소스 생성 실행
  Future<Map<String, dynamic>> _executeCreateResource(
    FixAction action,
    ErrorDiagnosis diagnosis,
  ) async {
    // 실제 구현에서는 누락된 리소스를 생성하는 로직이 들어갑니다
    return {
      'success': true,
      'data': {'resourceCreated': true},
    };
  }

  /// 재시도 실행
  Future<Map<String, dynamic>> _executeRetryWithDelay(
    FixAction action,
    ErrorDiagnosis diagnosis,
  ) async {
    final delay = action.parameters['delay'] as int? ?? 1000;
    
    // 지연 시간 대기
    await Future.delayed(Duration(milliseconds: delay));
    
    // 실제 구현에서는 API 요청을 재시도하는 로직이 들어갑니다
    return {
      'success': true,
      'data': {'retried': true, 'delay': delay},
    };
  }

  /// 데이터 타입 변환 실행
  Future<Map<String, dynamic>> _executeConvertDataType(
    FixAction action,
    ErrorDiagnosis diagnosis,
  ) async {
    final field = action.parameters['field'] as String?;
    final fromType = action.parameters['fromType'] as String?;
    final toType = action.parameters['toType'] as String?;
    final value = action.parameters['value'];
    
    if (field == null || fromType == null || toType == null) {
      return {'success': false, 'error': '타입 변환 정보가 부족합니다'};
    }
    
    // 타입 변환 로직
    dynamic convertedValue;
    try {
      if (toType == 'String') {
        convertedValue = value.toString();
      } else if (toType == 'int') {
        convertedValue = int.parse(value.toString());
      } else if (toType == 'double') {
        convertedValue = double.parse(value.toString());
      } else if (toType == 'bool') {
        convertedValue = value.toString().toLowerCase() == 'true';
      } else {
        convertedValue = value;
      }
    } catch (e) {
      return {'success': false, 'error': '타입 변환 실패: $e'};
    }
    
    return {
      'success': true,
      'data': {field: convertedValue},
    };
  }

  /// 권한 변경 실행
  Future<Map<String, dynamic>> _executeChangePermission(
    FixAction action,
    ErrorDiagnosis diagnosis,
  ) async {
    // 실제 구현에서는 토큰 갱신 등의 로직이 들어갑니다
    return {
      'success': true,
      'data': {'permissionUpdated': true},
    };
  }

  /// 성공 통계 가져오기
  Map<String, dynamic> getSuccessStatistics() {
    final totalAttempts = _fixAttempts.values.fold(0, (a, b) => a + b);
    final totalSuccesses = _successfulFixes.values.fold(0, (a, b) => a + b);
    
    return {
      'totalAttempts': totalAttempts,
      'successfulFixes': totalSuccesses,
      'successRate': totalAttempts > 0 ? totalSuccesses / totalAttempts : 0.0,
      'learnedPatterns': _getLearnedPatternsCount(),
      'averageFixDuration': _getAverageFixDuration(),
      'fixTypeDistribution': _getFixTypeDistribution(),
    };
  }

  /// 학습된 패턴 수 가져오기
  int _getLearnedPatternsCount() {
    // 실제 구현에서는 diagnostics에서 학습된 패턴 수를 가져옵니다
    return _fixHistory.length;
  }

  /// 평균 수정 시간 가져오기
  String _getAverageFixDuration() {
    if (_fixHistory.isEmpty) return '0ms';
    
    final totalDuration = _fixHistory
        .map((h) => h.fixResult.duration)
        .fold(0, (a, b) => a + b);
    
    final average = totalDuration ~/ _fixHistory.length;
    return '${average}ms';
  }

  /// 수정 타입 분포 가져오기
  Map<String, int> _getFixTypeDistribution() {
    final distribution = <String, int>{};
    
    for (final entry in _fixHistory) {
      final fixType = entry.context?['fixType']?.toString() ?? 'unknown';
      distribution[fixType] = (distribution[fixType] ?? 0) + 1;
    }
    
    return distribution;
  }

  /// 수정 이력 가져오기
  List<FixHistoryEntry> getFixHistory({int? limit}) {
    if (limit != null) {
      return _fixHistory.reversed.take(limit).toList();
    }
    return _fixHistory.reversed.toList();
  }

  /// 수정 이력 초기화
  void clearHistory() {
    _fixHistory.clear();
    _fixAttempts.clear();
    _successfulFixes.clear();
  }
}