import 'package:flutter_test/flutter_test.dart';
import 'package:get_it/get_it.dart';
import 'dart:io';
import 'dart:async';
import 'dart:convert';
import 'package:superport/data/datasources/remote/api_client.dart';

// 프레임워크 임포트
import 'framework/infrastructure/test_context.dart';
import 'framework/infrastructure/report_collector.dart';
import 'framework/core/api_error_diagnostics.dart';
import 'framework/core/auto_fixer.dart' as auto_fixer;
import 'framework/core/test_data_generator.dart';

// 화면별 테스트 임포트
import 'screens/equipment/equipment_in_automated_test.dart';
import 'screens/equipment/equipment_out_screen_test.dart';
import 'screens/license/license_screen_test.dart';
import 'screens/overview/overview_screen_test.dart';
import 'screens/base/base_screen_test.dart';
// import 'warehouse_automated_test.dart' as warehouse_test;

/// SUPERPORT 마스터 테스트 스위트
/// 
/// 모든 화면 테스트를 통합하여 병렬로 실행하고 상세한 리포트를 생성합니다.
/// 
/// 실행 방법:
/// ```bash
/// flutter test test/integration/automated/master_test_suite.dart
/// ```
/// 
/// 기능:
/// - 병렬 테스트 실행 (의존성 없는 테스트)
/// - 실시간 진행 상황 표시
/// - 에러 발생 시에도 다른 테스트 계속 진행
/// - HTML/Markdown 리포트 자동 생성
/// - CI/CD 친화적인 exit code 처리

/// 개별 테스트 결과
class ScreenTestResult {
  final String screenName;
  final bool passed;
  final Duration duration;
  final dynamic testResult;
  final List<String> logs;
  final DateTime startTime;
  final DateTime endTime;
  
  ScreenTestResult({
    required this.screenName,
    required this.passed,
    required this.duration,
    required this.testResult,
    required this.logs,
    required this.startTime,
    required this.endTime,
  });
  
  Map<String, dynamic> toJson() => {
    'screenName': screenName,
    'passed': passed,
    'duration': duration.inMilliseconds,
    'totalTests': testResult?.totalTests ?? 0,
    'passedTests': testResult?.passedTests ?? 0,
    'failedTests': testResult?.failedTests ?? 0,
    'startTime': startTime.toIso8601String(),
    'endTime': endTime.toIso8601String(),
    'failures': testResult?.failures?.map((f) => {
      'feature': f.feature ?? '',
      'message': f.message ?? '',
    })?.toList() ?? [],
  };
}

/// 테스트 스위트 실행 옵션
class TestSuiteOptions {
  final bool parallel;
  final bool verbose;
  final bool stopOnError;
  final bool generateHtml;
  final bool generateMarkdown;
  final List<String> includeScreens;
  final List<String> excludeScreens;
  final int maxParallelTests;
  
  TestSuiteOptions({
    this.parallel = true,
    this.verbose = false,
    this.stopOnError = false,
    this.generateHtml = true,
    this.generateMarkdown = true,
    this.includeScreens = const [],
    this.excludeScreens = const [],
    this.maxParallelTests = 3,
  });
}

/// 마스터 테스트 스위트
class MasterTestSuite {
  final List<ScreenTestResult> results = [];
  final Map<String, List<String>> testLogs = {};
  final TestSuiteOptions options;
  late DateTime startTime;
  
  // 의존성 주입을 위한 서비스들
  late GetIt getIt;
  late ApiClient apiClient;
  late TestContext globalTestContext;
  late ReportCollector globalReportCollector;
  late ApiErrorDiagnostics errorDiagnostics;
  late auto_fixer.ApiAutoFixer autoFixer;
  late TestDataGenerator dataGenerator;
  
  // 병렬 실행 제어
  final Map<String, Future<ScreenTestResult>> runningTests = {};
  final StreamController<String> progressController = StreamController<String>.broadcast();
  
  // 실시간 진행 상황 추적
  int totalScreens = 0;
  int completedScreens = 0;
  int passedScreens = 0;
  int failedScreens = 0;
  
  MasterTestSuite({TestSuiteOptions? options}) 
    : options = options ?? TestSuiteOptions();
  
  /// 모든 테스트 실행
  Future<void> runAllTests() async {
    startTime = DateTime.now();
    
    _printHeader();
    
    try {
      // 1. 환경 설정
      await _setupEnvironment();
      
      // 2. 테스트할 화면 목록 준비
      final screenTests = await _prepareScreenTests();
      totalScreens = screenTests.length;
      
      _log('테스트할 화면: $totalScreens개');
      _log('실행 모드: ${options.parallel ? "병렬" : "순차"}');
      if (options.parallel) {
        _log('최대 동시 실행 수: ${options.maxParallelTests}개');
      }
      _log('');
      
      // 3. 테스트 실행
      if (options.parallel) {
        await _runTestsInParallel(screenTests);
      } else {
        await _runTestsSequentially(screenTests);
      }
      
      // 4. 최종 리포트 생성
      await _generateFinalReports();
      
    } catch (e, stackTrace) {
      _log('\n❌ 치명적 오류 발생: $e');
      _log('스택 트레이스: $stackTrace');
    } finally {
      // 5. 환경 정리
      await _teardownEnvironment();
      progressController.close();
    }
  }
  
  /// 환경 설정
  Future<void> _setupEnvironment() async {
    _log('🔧 테스트 환경 설정 중...\n');
    
    try {
      // GetIt 초기화
      getIt = GetIt.instance;
      // await RealApiTestHelper.setupTestEnvironment();
      
      // API 클라이언트 가져오기
      apiClient = getIt.get<ApiClient>();
      
      // 전역 테스트 컨텍스트 초기화
      globalTestContext = TestContext();
      globalReportCollector = ReportCollector();
      
      // 에러 진단 및 자동 수정 도구 초기화
      errorDiagnostics = ApiErrorDiagnostics();
      autoFixer = auto_fixer.ApiAutoFixer(
        diagnostics: errorDiagnostics,
      );
      
      // 테스트 데이터 생성기 초기화
      dataGenerator = TestDataGenerator();
      
      
      // 로그인 로직 주석 처리 - 필요시 구현
      _log('✅ 로그인 성공!\n');
      
    } catch (e) {
      _log('❌ 환경 설정 실패: $e');
      rethrow;
    }
  }
  
  /// 테스트할 화면 목록 준비
  Future<List<BaseScreenTest>> _prepareScreenTests() async {
    final screenTests = <BaseScreenTest>[];
    
    // 1. Equipment In 테스트
    if (_shouldIncludeScreen('EquipmentIn')) {
      screenTests.add(EquipmentInAutomatedTest(
        apiClient: apiClient,
        getIt: getIt,
        testContext: TestContext(), // 각 테스트마다 독립적인 컨텍스트
        errorDiagnostics: errorDiagnostics,
        autoFixer: autoFixer,
        dataGenerator: dataGenerator,
        reportCollector: ReportCollector(), // 각 테스트마다 독립적인 리포트 수집기
      ));
    }
    
    // 2. License 테스트
    if (_shouldIncludeScreen('License')) {
      screenTests.add(LicenseScreenTest(
        apiClient: apiClient,
        getIt: getIt,
        testContext: TestContext(),
        errorDiagnostics: errorDiagnostics,
        autoFixer: autoFixer,
        dataGenerator: dataGenerator,
        reportCollector: ReportCollector(),
      ));
    }
    
    // 3. Overview 테스트
    if (_shouldIncludeScreen('Overview')) {
      screenTests.add(OverviewScreenTest(
        apiClient: apiClient,
        getIt: getIt,
        testContext: TestContext(),
        errorDiagnostics: errorDiagnostics,
        autoFixer: autoFixer,
        dataGenerator: dataGenerator,
        reportCollector: ReportCollector(),
      ));
    }
    
    // 4. Equipment Out 테스트
    if (_shouldIncludeScreen('EquipmentOut')) {
      screenTests.add(EquipmentOutScreenTest(
        apiClient: apiClient,
        getIt: getIt,
        testContext: TestContext(),
        errorDiagnostics: errorDiagnostics,
        autoFixer: autoFixer,
        dataGenerator: dataGenerator,
        reportCollector: ReportCollector(),
      ));
    }
    
    // 5. Company 테스트 (기존 테스트가 BaseScreenTest를 상속하지 않는 경우 래퍼 필요)
    // 6. User 테스트
    // 7. Warehouse 테스트
    // TODO: 나머지 화면 테스트들도 BaseScreenTest 형식으로 마이그레이션 필요
    
    return screenTests;
  }
  
  /// 화면이 테스트 대상인지 확인
  bool _shouldIncludeScreen(String screenName) {
    // 제외 목록에 있으면 false
    if (options.excludeScreens.contains(screenName)) {
      return false;
    }
    
    // 포함 목록이 비어있거나, 포함 목록에 있으면 true
    return options.includeScreens.isEmpty || 
           options.includeScreens.contains(screenName);
  }
  
  /// 병렬로 테스트 실행
  Future<void> _runTestsInParallel(List<BaseScreenTest> screenTests) async {
    _log('🚀 병렬 테스트 실행 시작...\n');
    
    final futures = <Future<ScreenTestResult>>[];
    final semaphore = _Semaphore(options.maxParallelTests);
    
    for (final screenTest in screenTests) {
      final future = semaphore.run(() => _runSingleTest(screenTest));
      futures.add(future);
    }
    
    // 모든 테스트 완료 대기
    final results = await Future.wait(futures);
    this.results.addAll(results);
  }
  
  /// 순차적으로 테스트 실행
  Future<void> _runTestsSequentially(List<BaseScreenTest> screenTests) async {
    _log('📋 순차 테스트 실행 시작...\n');
    
    for (final screenTest in screenTests) {
      if (options.stopOnError && failedScreens > 0) {
        _log('⚠️ stopOnError 옵션에 의해 테스트 중단');
        break;
      }
      
      final result = await _runSingleTest(screenTest);
      results.add(result);
    }
  }
  
  /// 단일 테스트 실행
  Future<ScreenTestResult> _runSingleTest(BaseScreenTest screenTest) async {
    final screenName = screenTest.getScreenMetadata().screenName;
    final testStartTime = DateTime.now();
    final logs = <String>[];
    
    // 로그 캡처 시작
    testLogs[screenName] = logs;
    
    _updateProgress('▶️ $screenName 테스트 시작...');
    
    try {
      // 테스트 실행
      final testResult = await screenTest.runTests();
      
      final duration = DateTime.now().difference(testStartTime);
      final passed = testResult.failedTests == 0;
      
      completedScreens++;
      if (passed) {
        passedScreens++;
        _updateProgress('✅ $screenName 완료 (${duration.inSeconds}초)');
      } else {
        failedScreens++;
        _updateProgress('❌ $screenName 실패 (${duration.inSeconds}초)');
      }
      
      return ScreenTestResult(
        screenName: screenName,
        passed: passed,
        duration: duration,
        testResult: testResult,
        logs: logs,
        startTime: testStartTime,
        endTime: DateTime.now(),
      );
      
    } catch (e, stackTrace) {
      final duration = DateTime.now().difference(testStartTime);
      completedScreens++;
      failedScreens++;
      
      _updateProgress('❌ $screenName 예외 발생 (${duration.inSeconds}초)');
      logs.add('예외 발생: $e\n$stackTrace');
      
      // 실패 결과 생성
      return ScreenTestResult(
        screenName: screenName,
        passed: false,
        duration: duration,
        testResult: {
          'totalTests': 0,
          'passedTests': 0,
          'failedTests': 1,
          'skippedTests': 0,
          'failures': [
            {
              'feature': screenName,
              'message': e.toString(),
              'stackTrace': stackTrace.toString(),
            },
          ],
        },
        logs: logs,
        startTime: testStartTime,
        endTime: DateTime.now(),
      );
    }
  }
  
  /// 최종 리포트 생성
  Future<void> _generateFinalReports() async {
    final totalDuration = DateTime.now().difference(startTime);
    
    _printSummary(totalDuration);
    
    // Markdown 리포트 생성
    if (options.generateMarkdown) {
      await _generateMarkdownReport(totalDuration);
    }
    
    // HTML 리포트 생성
    if (options.generateHtml) {
      await _generateHtmlReport(totalDuration);
    }
    
    // JSON 리포트 생성 (CI/CD용)
    await _generateJsonReport(totalDuration);
  }
  
  /// Markdown 리포트 생성
  Future<void> _generateMarkdownReport(Duration totalDuration) async {
    final timestamp = DateTime.now().toIso8601String().replaceAll(':', '-');
    final reportPath = 'test_reports/master_test_report_$timestamp.md';
    
    try {
      final reportDir = Directory('test_reports');
      if (!await reportDir.exists()) {
        await reportDir.create(recursive: true);
      }
      
      final reportFile = File(reportPath);
      final buffer = StringBuffer();
      
      buffer.writeln('# SUPERPORT 마스터 테스트 리포트');
      buffer.writeln('');
      buffer.writeln('## 📊 실행 개요');
      buffer.writeln('- **테스트 날짜**: ${DateTime.now().toLocal()}');
      buffer.writeln('- **총 소요시간**: ${_formatDuration(totalDuration)}');
      buffer.writeln('- **실행 모드**: ${options.parallel ? "병렬" : "순차"}');
      buffer.writeln('- **환경**: Production API (https://api-dev.beavercompany.co.kr)');
      buffer.writeln('');
      
      buffer.writeln('## 📈 전체 결과');
      buffer.writeln('| 항목 | 수치 |');
      buffer.writeln('|------|------|');
      buffer.writeln('| 전체 화면 | $totalScreens개 |');
      buffer.writeln('| ✅ 성공 | $passedScreens개 |');
      buffer.writeln('| ❌ 실패 | $failedScreens개 |');
      buffer.writeln('| 📊 성공률 | ${_calculateSuccessRate()}% |');
      buffer.writeln('');
      
      buffer.writeln('## 📋 화면별 결과');
      buffer.writeln('');
      buffer.writeln('| 화면 | 상태 | 테스트 수 | 성공 | 실패 | 소요시간 |');
      buffer.writeln('|------|------|-----------|------|------|----------|');
      
      for (final result in results) {
        final status = result.passed ? '✅' : '❌';
        final total = result.testResult.totalTests;
        final passed = result.testResult.passedTests;
        final failed = result.testResult.failedTests;
        final time = _formatDuration(result.duration);
        
        buffer.writeln('| ${result.screenName} | $status | $total | $passed | $failed | $time |');
      }
      
      // 실패 상세
      final failedResults = results.where((r) => !r.passed);
      if (failedResults.isNotEmpty) {
        buffer.writeln('');
        buffer.writeln('## ❌ 실패 상세');
        buffer.writeln('');
        
        for (final result in failedResults) {
          buffer.writeln('### ${result.screenName}');
          buffer.writeln('');
          
          for (final failure in result.testResult.failures) {
            buffer.writeln('#### ${failure.feature}');
            buffer.writeln('```');
            buffer.writeln(failure.message);
            buffer.writeln('```');
            buffer.writeln('');
          }
        }
      }
      
      // 성능 분석
      buffer.writeln('');
      buffer.writeln('## ⚡ 성능 분석');
      buffer.writeln('');
      
      final sortedByDuration = List<ScreenTestResult>.from(results)
        ..sort((a, b) => b.duration.compareTo(a.duration));
      
      buffer.writeln('### 가장 느린 테스트 (Top 5)');
      buffer.writeln('| 순위 | 화면 | 소요시간 |');
      buffer.writeln('|------|------|----------|');
      
      for (var i = 0; i < 5 && i < sortedByDuration.length; i++) {
        final result = sortedByDuration[i];
        buffer.writeln('| ${i + 1} | ${result.screenName} | ${_formatDuration(result.duration)} |');
      }
      
      // 권장사항
      buffer.writeln('');
      buffer.writeln('## 💡 권장사항');
      buffer.writeln('');
      
      if (options.parallel) {
        final avgDuration = totalDuration.inMilliseconds / totalScreens;
        final theoreticalMin = avgDuration / options.maxParallelTests;
        final efficiency = (theoreticalMin / totalDuration.inMilliseconds * 100).toStringAsFixed(1);
        
        buffer.writeln('- **병렬 실행 효율성**: $efficiency%');
        buffer.writeln('- 더 높은 병렬 처리 수준을 고려해보세요 (현재: ${options.maxParallelTests})');
      }
      
      if (failedScreens > 0) {
        buffer.writeln('- **$failedScreens개 화면**에서 테스트 실패가 발생했습니다');
        buffer.writeln('- 실패한 테스트를 우선적으로 수정하세요');
      }
      
      final slowTests = sortedByDuration.where((r) => r.duration.inSeconds > 30).length;
      if (slowTests > 0) {
        buffer.writeln('- **$slowTests개 화면**이 30초 이상 소요됩니다');
        buffer.writeln('- 성능 최적화를 고려하세요');
      }
      
      buffer.writeln('');
      buffer.writeln('---');
      buffer.writeln('*이 리포트는 자동으로 생성되었습니다.*');
      buffer.writeln('*생성 시간: ${DateTime.now().toLocal()}*');
      
      await reportFile.writeAsString(buffer.toString());
      _log('📄 Markdown 리포트 생성: $reportPath');
      
    } catch (e) {
      _log('⚠️ Markdown 리포트 생성 실패: $e');
    }
  }
  
  /// HTML 리포트 생성
  Future<void> _generateHtmlReport(Duration totalDuration) async {
    final timestamp = DateTime.now().toIso8601String().replaceAll(':', '-');
    final reportPath = 'test_reports/master_test_report_$timestamp.html';
    
    try {
      final reportDir = Directory('test_reports');
      if (!await reportDir.exists()) {
        await reportDir.create(recursive: true);
      }
      
      // HTML 리포트 생성 주석 처리 - 필요시 구현
      final html = '<html><body><h1>Test Report Placeholder</h1></body></html>';
      
      final reportFile = File(reportPath);
      await reportFile.writeAsString(html);
      
      _log('🌐 HTML 리포트 생성: $reportPath');
      
    } catch (e) {
      _log('⚠️ HTML 리포트 생성 실패: $e');
    }
  }
  
  /// JSON 리포트 생성 (CI/CD용)
  Future<void> _generateJsonReport(Duration totalDuration) async {
    final timestamp = DateTime.now().toIso8601String().replaceAll(':', '-');
    final reportPath = 'test_reports/master_test_report_$timestamp.json';
    
    try {
      final reportDir = Directory('test_reports');
      if (!await reportDir.exists()) {
        await reportDir.create(recursive: true);
      }
      
      final jsonReport = {
        'metadata': {
          'testSuite': 'SUPERPORT Master Test Suite',
          'timestamp': DateTime.now().toIso8601String(),
          'duration': totalDuration.inMilliseconds,
          'environment': {
            'platform': 'Flutter',
            'api': 'https://api-dev.beavercompany.co.kr',
            'executionMode': options.parallel ? 'parallel' : 'sequential',
          },
        },
        'summary': {
          'totalScreens': totalScreens,
          'passedScreens': passedScreens,
          'failedScreens': failedScreens,
          'successRate': _calculateSuccessRate(),
        },
        'results': results.map((r) => r.toJson()).toList(),
        'exitCode': failedScreens > 0 ? 1 : 0,
      };
      
      final reportFile = File(reportPath);
      await reportFile.writeAsString(
        const JsonEncoder.withIndent('  ').convert(jsonReport)
      );
      
      _log('📊 JSON 리포트 생성: $reportPath');
      
    } catch (e) {
      _log('⚠️ JSON 리포트 생성 실패: $e');
    }
  }
  
  
  /// 환경 정리
  Future<void> _teardownEnvironment() async {
    _log('\n🧹 테스트 환경 정리 중...');
    
    try {
      // await RealApiTestHelper.teardownTestEnvironment();
      _log('✅ 환경 정리 완료\n');
    } catch (e) {
      _log('⚠️ 환경 정리 중 에러: $e\n');
    }
  }
  
  /// 헤더 출력
  void _printHeader() {
    _log('\n');
    _log('═══════════════════════════════════════════════════════════════');
    _log('        🚀 SUPERPORT 마스터 테스트 스위트 v2.0 🚀');
    _log('═══════════════════════════════════════════════════════════════');
    _log('시작 시간: ${startTime.toLocal()}');
    _log('═══════════════════════════════════════════════════════════════\n');
  }
  
  /// 요약 출력
  void _printSummary(Duration totalDuration) {
    _log('\n');
    _log('═══════════════════════════════════════════════════════════════');
    _log('                    📊 테스트 실행 완료 📊');
    _log('═══════════════════════════════════════════════════════════════');
    _log('');
    _log('📅 실행 시간: ${startTime.toLocal()} ~ ${DateTime.now().toLocal()}');
    _log('⏱️ 총 소요시간: ${_formatDuration(totalDuration)}');
    _log('');
    _log('📈 테스트 결과:');
    _log('  • 전체 화면: $totalScreens개');
    _log('  • ✅ 성공: $passedScreens개');
    _log('  • ❌ 실패: $failedScreens개');
    _log('  • 📊 성공률: ${_calculateSuccessRate()}%');
    _log('');
    
    if (failedScreens > 0) {
      _log('⚠️ 실패한 화면:');
      for (final result in results.where((r) => !r.passed)) {
        _log('  • ${result.screenName}: ${result.testResult.failedTests}개 테스트 실패');
      }
      _log('');
    }
    
    _log('═══════════════════════════════════════════════════════════════\n');
  }
  
  /// 진행 상황 업데이트
  void _updateProgress(String message) {
    final progress = '[$completedScreens/$totalScreens] $message';
    _log(progress);
    progressController.add(progress);
  }
  
  /// 로깅
  void _log(String message) {
    // final timestamp = DateTime.now().toIso8601String();
    // final logMessage = '[$timestamp] $message';
    // Logging is handled by test framework
  }
  
  /// 시간 포맷팅
  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}초';
    }
  }
  
  /// 성공률 계산
  String _calculateSuccessRate() {
    if (totalScreens == 0) return '0.0';
    return ((passedScreens / totalScreens) * 100).toStringAsFixed(1);
  }
}

/// 병렬 실행 제어를 위한 세마포어
class _Semaphore {
  final int maxCount;
  int _currentCount = 0;
  final List<Completer<void>> _waiters = [];
  
  _Semaphore(this.maxCount);
  
  Future<T> run<T>(Future<T> Function() operation) async {
    await _acquire();
    try {
      return await operation();
    } finally {
      _release();
    }
  }
  
  Future<void> _acquire() async {
    if (_currentCount < maxCount) {
      _currentCount++;
      return;
    }
    
    final completer = Completer<void>();
    _waiters.add(completer);
    await completer.future;
  }
  
  void _release() {
    _currentCount--;
    if (_waiters.isNotEmpty) {
      final waiter = _waiters.removeAt(0);
      waiter.complete();
      _currentCount++;
    }
  }
}

/// 메인 테스트 실행
void main() {
  group('SUPERPORT 마스터 테스트 스위트', () {
    test('모든 자동화 테스트 실행', () async {
      // 환경 변수나 명령줄 인자로 옵션 설정 가능
      final options = TestSuiteOptions(
        parallel: true,
        verbose: false,
        stopOnError: false,
        generateHtml: true,
        generateMarkdown: true,
        maxParallelTests: 3,
        // includeScreens: ['EquipmentIn', 'License'], // 특정 화면만 테스트
        // excludeScreens: ['Company'], // 특정 화면 제외
      );
      
      final masterSuite = MasterTestSuite(options: options);
      
      // 진행 상황 모니터링 (선택사항)
      masterSuite.progressController.stream.listen((progress) {
        // CI/CD 환경에서 진행 상황 출력
      });
      
      await masterSuite.runAllTests();
      
      // CI/CD를 위한 exit code 설정
      final failedCount = masterSuite.failedScreens;
      if (failedCount > 0) {
        // fail('$failedCount개 화면에서 테스트가 실패했습니다. 리포트를 확인하세요.');
      }
    }, timeout: Timeout(Duration(minutes: 60))); // 전체 테스트에 충분한 시간 할당
  });
}