import 'dart:convert';
import 'dart:io';
import '../models/report_models.dart';
import '../utils/html_report_generator.dart';

/// 테스트 결과 리포트 수집기
class ReportCollector {
  final List<StepReport> _steps = [];
  final List<ErrorReport> _errors = [];
  final List<AutoFixReport> _autoFixes = [];
  final Map<String, FeatureReport> _features = {};
  final Map<String, List<ApiCallReport>> _apiCalls = {};
  final DateTime _startTime = DateTime.now();
  
  /// 테스트 단계 추가
  void addStep(StepReport step) {
    _steps.add(step);
  }
  
  /// 에러 추가
  void addError(ErrorReport error) {
    _errors.add(error);
  }
  
  /// 자동 수정 추가
  void addAutoFix(AutoFixReport fix) {
    _autoFixes.add(fix);
  }
  
  /// API 호출 추가
  void addApiCall(String feature, ApiCallReport apiCall) {
    _apiCalls.putIfAbsent(feature, () => []).add(apiCall);
  }
  
  /// 테스트 결과 추가 (간단한 버전)
  void addTestResult({
    required String screenName,
    required String testName,
    required bool passed,
    String? error,
  }) {
    final step = StepReport(
      stepName: testName,
      timestamp: DateTime.now(),
      message: passed ? '테스트 성공' : '테스트 실패: ${error ?? '알 수 없는 오류'}',
      success: passed,
      details: {
        'screenName': screenName,
        'testName': testName,
        'passed': passed,
        if (error != null) 'error': error,
      },
    );
    addStep(step);
    
    // 기능별 리포트에도 추가
    final feature = _features[screenName] ?? FeatureReport(
      featureName: screenName,
      featureType: FeatureType.screen,
      success: true,
      totalTests: 0,
      passedTests: 0,
      failedTests: 0,
      totalDuration: Duration.zero,
      testCaseReports: [],
    );
    
    _features[screenName] = FeatureReport(
      featureName: feature.featureName,
      featureType: feature.featureType,
      success: feature.passedTests + (passed ? 1 : 0) == feature.totalTests + 1,
      totalTests: feature.totalTests + 1,
      passedTests: feature.passedTests + (passed ? 1 : 0),
      failedTests: feature.failedTests + (passed ? 0 : 1),
      totalDuration: feature.totalDuration,
      testCaseReports: [
        ...feature.testCaseReports,
        TestCaseReport(
          testCaseName: testName,
          steps: [],
          success: passed,
          duration: Duration.zero,
          errorMessage: error,
        ),
      ],
    );
  }
  
  /// 기능 리포트 추가
  void addFeatureReport(String feature, FeatureReport report) {
    _features[feature] = report;
  }
  
  /// 테스트 결과 생성
  TestResult generateTestResult() {
    int totalTests = 0;
    int passedTests = 0;
    int failedTests = 0;
    int skippedTests = 0;
    final List<TestFailure> failures = [];
    
    // 각 기능별 테스트 결과 집계
    _features.forEach((feature, report) {
      totalTests += report.totalTests;
      passedTests += report.passedTests;
      failedTests += report.failedTests;
      
      // 실패한 테스트 케이스들을 TestFailure로 변환
      for (final testCase in report.testCaseReports) {
        if (!testCase.success && testCase.errorMessage != null) {
          failures.add(TestFailure(
            feature: feature,
            message: testCase.errorMessage!,
            stackTrace: testCase.stackTrace,
          ));
        }
      }
    });
    
    // 단계별 실패도 집계
    for (final step in _steps) {
      if (!step.success && step.message.contains('실패')) {
        failures.add(TestFailure(
          feature: step.stepName,
          message: step.message,
        ));
      }
    }
    
    return TestResult(
      totalTests: totalTests == 0 ? _steps.length : totalTests,
      passedTests: passedTests == 0 ? _steps.where((s) => s.success).length : passedTests,
      failedTests: failedTests == 0 ? _steps.where((s) => !s.success).length : failedTests,
      skippedTests: skippedTests,
      failures: failures,
    );
  }
  
  /// 전체 리포트 생성 (BasicTestReport 사용)
  BasicTestReport generateReport() {
    final endTime = DateTime.now();
    final duration = endTime.difference(_startTime);
    
    return BasicTestReport(
      reportId: 'TEST-${DateTime.now().millisecondsSinceEpoch}',
      testName: 'Automated Test Suite',
      startTime: _startTime,
      endTime: endTime,
      duration: duration,
      environment: {
        'platform': 'Flutter',
        'dartVersion': '3.0',
        'testFramework': 'flutter_test',
      },
      testResult: generateTestResult(),
      steps: List.from(_steps),
      errors: List.from(_errors),
      autoFixes: List.from(_autoFixes),
      features: Map.from(_features),
      apiCalls: Map.from(_apiCalls),
      summary: _generateSummary(),
    );
  }
  
  /// 자동 수정 목록 조회
  List<AutoFixReport> getAutoFixes() {
    return List.from(_autoFixes);
  }
  
  /// 에러 목록 조회
  List<ErrorReport> getErrors() {
    return List.from(_errors);
  }
  
  /// 기능별 리포트 조회
  Map<String, FeatureReport> getFeatureReports() {
    return Map.from(_features);
  }
  
  /// 요약 생성
  String _generateSummary() {
    final buffer = StringBuffer();
    final testResult = generateTestResult();
    
    buffer.writeln('테스트 실행 요약:');
    buffer.writeln('- 전체 테스트: ${testResult.totalTests}개');
    buffer.writeln('- 성공: ${testResult.passedTests}개');
    buffer.writeln('- 실패: ${testResult.failedTests}개');
    
    if (_autoFixes.isNotEmpty) {
      buffer.writeln('\n자동 수정 요약:');
      buffer.writeln('- 총 ${_autoFixes.length}개 항목 자동 수정됨');
      final fixTypes = _autoFixes.map((f) => f.errorType).toSet();
      for (final type in fixTypes) {
        final count = _autoFixes.where((f) => f.errorType == type).length;
        buffer.writeln('  - $type: $count개');
      }
    }
    
    if (_errors.isNotEmpty) {
      buffer.writeln('\n에러 요약:');
      buffer.writeln('- 총 ${_errors.length}개 에러 발생');
      final errorTypes = _errors.map((e) => e.errorType).toSet();
      for (final type in errorTypes) {
        final count = _errors.where((e) => e.errorType == type).length;
        buffer.writeln('  - $type: $count개');
      }
    }
    
    return buffer.toString();
  }
  
  /// 리포트 초기화
  void clear() {
    _steps.clear();
    _errors.clear();
    _autoFixes.clear();
    _features.clear();
    _apiCalls.clear();
  }
  
  /// 통계 정보 조회
  Map<String, dynamic> getStatistics() {
    return {
      'totalSteps': _steps.length,
      'successfulSteps': _steps.where((s) => s.success).length,
      'failedSteps': _steps.where((s) => !s.success).length,
      'totalErrors': _errors.length,
      'totalAutoFixes': _autoFixes.length,
      'totalFeatures': _features.length,
      'totalApiCalls': _apiCalls.values.expand((calls) => calls).length,
      'duration': DateTime.now().difference(_startTime).inSeconds,
    };
  }
  
  /// HTML 리포트 생성
  Future<String> generateHtmlReport() async {
    final report = generateReport();
    final generator = HtmlReportGenerator();
    return await generator.generateReport(report);
  }
  
  /// Markdown 리포트 생성
  Future<String> generateMarkdownReport() async {
    final report = generateReport();
    final buffer = StringBuffer();
    
    // 헤더
    buffer.writeln('# ${report.testName}');
    buffer.writeln();
    buffer.writeln('## 📊 테스트 실행 결과');
    buffer.writeln();
    buffer.writeln('- **실행 시간**: ${report.startTime.toLocal()} ~ ${report.endTime.toLocal()}');
    buffer.writeln('- **소요 시간**: ${_formatDuration(report.duration)}');
    buffer.writeln('- **환경**: ${report.environment['platform']} (${report.environment['api']})');
    buffer.writeln();
    
    // 요약
    buffer.writeln('## 📈 테스트 요약');
    buffer.writeln();
    buffer.writeln('| 항목 | 수치 |');
    buffer.writeln('|------|------|');
    buffer.writeln('| 전체 테스트 | ${report.testResult.totalTests} |');
    buffer.writeln('| ✅ 성공 | ${report.testResult.passedTests} |');
    buffer.writeln('| ❌ 실패 | ${report.testResult.failedTests} |');
    buffer.writeln('| ⏭️ 건너뜀 | ${report.testResult.skippedTests} |');
    
    final successRate = report.testResult.totalTests > 0
        ? (report.testResult.passedTests / report.testResult.totalTests * 100).toStringAsFixed(1)
        : '0.0';
    buffer.writeln('| 성공률 | $successRate% |');
    buffer.writeln();
    
    // 기능별 결과
    if (report.features.isNotEmpty) {
      buffer.writeln('## 🎯 기능별 테스트 결과');
      buffer.writeln();
      buffer.writeln('| 기능 | 전체 | 성공 | 실패 | 성공률 |');
      buffer.writeln('|------|------|------|------|--------|');
      
      report.features.forEach((name, feature) {
        final featureSuccessRate = feature.totalTests > 0
            ? (feature.passedTests / feature.totalTests * 100).toStringAsFixed(1)
            : '0.0';
        buffer.writeln('| $name | ${feature.totalTests} | ${feature.passedTests} | ${feature.failedTests} | $featureSuccessRate% |');
      });
      buffer.writeln();
    }
    
    // 실패 상세
    if (report.testResult.failures.isNotEmpty) {
      buffer.writeln('## ❌ 실패한 테스트');
      buffer.writeln();
      
      for (final failure in report.testResult.failures) {
        buffer.writeln('### ${failure.feature}');
        buffer.writeln();
        buffer.writeln('```');
        buffer.writeln(failure.message);
        buffer.writeln('```');
        buffer.writeln();
      }
    }
    
    // 자동 수정
    if (report.autoFixes.isNotEmpty) {
      buffer.writeln('## 🔧 자동 수정 내역');
      buffer.writeln();
      
      for (final fix in report.autoFixes) {
        final status = fix.success ? '✅' : '❌';
        buffer.writeln('- $status **${fix.errorType}**: ${fix.cause} → ${fix.solution}');
      }
      buffer.writeln();
    }
    
    buffer.writeln('---');
    buffer.writeln('*이 리포트는 ${DateTime.now().toLocal()}에 자동 생성되었습니다.*');
    
    return buffer.toString();
  }
  
  /// JSON 리포트 생성
  Future<String> generateJsonReport() async {
    final report = generateReport();
    final stats = getStatistics();
    
    final jsonData = {
      'reportId': report.reportId,
      'testName': report.testName,
      'timestamp': DateTime.now().toIso8601String(),
      'duration': report.duration.inMilliseconds,
      'environment': report.environment,
      'summary': {
        'totalTests': report.testResult.totalTests,
        'passedTests': report.testResult.passedTests,
        'failedTests': report.testResult.failedTests,
        'skippedTests': report.testResult.skippedTests,
        'successRate': report.testResult.totalTests > 0
            ? (report.testResult.passedTests / report.testResult.totalTests * 100).toStringAsFixed(1)
            : '0.0',
      },
      'statistics': stats,
      'features': report.features.map((key, value) => MapEntry(key, {
        'totalTests': value.totalTests,
        'passedTests': value.passedTests,
        'failedTests': value.failedTests,
      })),
      'failures': report.testResult.failures.map((f) => {
        'feature': f.feature,
        'message': f.message,
        'stackTrace': f.stackTrace,
      }).toList(),
      'autoFixes': report.autoFixes.map((f) => {
        'errorType': f.errorType,
        'cause': f.cause,
        'solution': f.solution,
        'success': f.success,
        'beforeData': f.beforeData,
        'afterData': f.afterData,
      }).toList(),
    };
    
    return const JsonEncoder.withIndent('  ').convert(jsonData);
  }
  
  /// 리포트 파일로 저장
  Future<void> saveReport(String content, String filePath) async {
    final file = File(filePath);
    final directory = file.parent;
    
    if (!await directory.exists()) {
      await directory.create(recursive: true);
    }
    
    await file.writeAsString(content);
  }
  
  /// Duration 포맷팅
  String _formatDuration(Duration duration) {
    if (duration.inHours > 0) {
      return '${duration.inHours}시간 ${duration.inMinutes % 60}분 ${duration.inSeconds % 60}초';
    } else if (duration.inMinutes > 0) {
      return '${duration.inMinutes}분 ${duration.inSeconds % 60}초';
    } else {
      return '${duration.inSeconds}초';
    }
  }
}