import 'dart:async';
import 'package:flutter_test/flutter_test.dart';
import '../models/test_models.dart' as test_models;
import '../models/error_models.dart';
import '../models/report_models.dart' as report_models;
import '../infrastructure/test_context.dart';
import '../infrastructure/report_collector.dart';
import 'api_error_diagnostics.dart';
import 'auto_fixer.dart' as auto_fixer;
import 'package:dio/dio.dart';
import 'test_data_generator.dart';

/// 화면 테스트 프레임워크의 추상 클래스
abstract class ScreenTestFramework {
  final TestContext testContext;
  final ApiErrorDiagnostics errorDiagnostics;
  final auto_fixer.ApiAutoFixer autoFixer;
  final TestDataGenerator dataGenerator;
  final ReportCollector reportCollector;
  
  ScreenTestFramework({
    required this.testContext,
    required this.errorDiagnostics,
    required this.autoFixer,
    required this.dataGenerator,
    required this.reportCollector,
  });
  
  /// 화면의 테스트 가능한 기능들을 자동으로 감지
  Future<List<test_models.TestableFeature>> detectFeatures(test_models.ScreenMetadata metadata) async {
    final features = <test_models.TestableFeature>[];
    
    // CRUD 작업 감지
    if (metadata.screenCapabilities.containsKey('crud')) {
      features.add(_createCrudFeature(metadata));
    }
    
    // 검색 기능 감지
    if (metadata.screenCapabilities.containsKey('search')) {
      features.add(_createSearchFeature(metadata));
    }
    
    // 필터링 기능 감지
    if (metadata.screenCapabilities.containsKey('filter')) {
      features.add(_createFilterFeature(metadata));
    }
    
    // 페이지네이션 감지
    if (metadata.screenCapabilities.containsKey('pagination')) {
      features.add(_createPaginationFeature(metadata));
    }
    
    // 커스텀 기능 감지 (하위 클래스에서 구현)
    features.addAll(await detectCustomFeatures(metadata));
    
    return features;
  }
  
  /// 하위 클래스에서 구현할 커스텀 기능 감지
  Future<List<test_models.TestableFeature>> detectCustomFeatures(test_models.ScreenMetadata metadata);
  
  /// 테스트 실행
  Future<report_models.TestResult> executeTests(List<test_models.TestableFeature> features) async {
    // report_models.TestResult 생성
    int totalTests = 0;
    int passedTests = 0;
    int failedTests = 0;
    int skippedTests = 0;
    final failures = <report_models.TestFailure>[];
    
    final testResult = test_models.TestResult(
      screenName: testContext.currentScreen ?? 'unknown',
      startTime: DateTime.now(),
    );
    
    for (final feature in features) {
      try {
        final featureResult = await _executeFeatureTests(feature);
        testResult.featureResults.add(featureResult);
      } catch (error, stackTrace) {
        final testError = test_models.TestError(
          message: error.toString(),
          stackTrace: stackTrace,
          feature: feature.featureName,
          timestamp: DateTime.now(),
        );
        
        // 에러 처리 시도
        await handleError(testError);
        testResult.errors.add(testError);
      }
    }
    
    testResult.endTime = DateTime.now();
    testResult.calculateMetrics();
    
    // 메트릭 계산
    for (final featureResult in testResult.featureResults) {
      for (final testCaseResult in featureResult.testCaseResults) {
        totalTests++;
        if (testCaseResult.success) {
          passedTests++;
        } else {
          failedTests++;
          failures.add(report_models.TestFailure(
            feature: featureResult.featureName,
            message: testCaseResult.error ?? 'Unknown error',
            stackTrace: testCaseResult.stackTrace?.toString(),
          ));
        }
      }
    }
    
    // report_models.TestResult 반환
    return report_models.TestResult(
      totalTests: totalTests,
      passedTests: passedTests,
      failedTests: failedTests,
      skippedTests: skippedTests,
      failures: failures,
    );
  }
  
  /// 에러 처리
  Future<void> handleError(test_models.TestError error) async {
    // 에러 진단
    final diagnosis = await errorDiagnostics.diagnose(
      ApiError(
        originalError: DioException(
          requestOptions: RequestOptions(path: '/test'),
          message: error.message,
          stackTrace: error.stackTrace,
        ),
        requestUrl: '/test',
        requestMethod: 'TEST',
        message: error.message,
      ),
    );
    
    // 자동 수정 시도
    if (diagnosis.confidence > 0.7) {
      final suggestions = await errorDiagnostics.suggestFixes(
        diagnosis,
      );
      
      if (suggestions.isNotEmpty) {
        final fixResult = await autoFixer.attemptAutoFix(ErrorDiagnosis(
          type: ApiErrorType.unknown,
          errorType: ErrorType.unknown,
          description: error.message,
          context: {},
          confidence: 0.8,
          affectedEndpoints: [],
        ));
        
        if (fixResult.success) {
          // TODO: Fix 결과 기록 로직 구현 필요
          // testContext.recordFix(fixResult);
        }
      }
    }
  }
  
  /// 리포트 생성
  Future<report_models.TestReport> generateReport() async {
    final basicReport = reportCollector.generateReport();
    
    // BasicTestReport를 TestReport로 변환
    return report_models.TestReport(
      reportId: basicReport.reportId,
      generatedAt: basicReport.endTime,
      type: report_models.ReportType.full,
      screenReports: [],
      summary: report_models.TestSummary(
        totalScreens: 1,
        totalFeatures: basicReport.features.length,
        totalTestCases: basicReport.testResult.totalTests,
        passedTestCases: basicReport.testResult.passedTests,
        failedTestCases: basicReport.testResult.failedTests,
        skippedTestCases: basicReport.testResult.skippedTests,
        totalDuration: basicReport.duration,
        overallSuccessRate: basicReport.testResult.passedTests / 
          (basicReport.testResult.totalTests > 0 ? basicReport.testResult.totalTests : 1),
        startTime: basicReport.startTime,
        endTime: basicReport.endTime,
      ),
      errorAnalyses: [],
      performanceMetrics: [],
      metadata: basicReport.environment,
    );
  }
  
  /// 개별 기능 테스트 실행
  Future<test_models.FeatureTestResult> _executeFeatureTests(test_models.TestableFeature feature) async {
    final result = test_models.FeatureTestResult(
      featureName: feature.featureName,
      startTime: DateTime.now(),
    );
    
    // 테스트 데이터 생성
    final testData = await dataGenerator.generate(
      test_models.GenerationStrategy(
        dataType: feature.requiredDataType ?? Object,
        fields: [],
        relationships: [],
        constraints: feature.dataConstraints ?? {},
        quantity: feature.testCases.length,
      ),
    );
    
    // 각 테스트 케이스 실행
    for (final testCase in feature.testCases) {
      final caseResult = await _executeTestCase(testCase, testData);
      result.testCaseResults.add(caseResult);
    }
    
    result.endTime = DateTime.now();
    result.calculateMetrics();
    
    return result;
  }
  
  /// 개별 테스트 케이스 실행
  Future<test_models.TestCaseResult> _executeTestCase(
    test_models.TestCase testCase,
    test_models.TestData testData,
  ) async {
    final stopwatch = Stopwatch()..start();
    
    try {
      // 전처리
      await testCase.setup?.call(testData);
      
      // 테스트 실행
      await testCase.execute(testData);
      
      // 검증
      await testCase.verify(testData);
      
      stopwatch.stop();
      
      return test_models.TestCaseResult(
        testCaseName: testCase.name,
        success: true,
        duration: stopwatch.elapsed,
      );
    } catch (error, stackTrace) {
      stopwatch.stop();
      
      return test_models.TestCaseResult(
        testCaseName: testCase.name,
        success: false,
        duration: stopwatch.elapsed,
        error: error.toString(),
        stackTrace: stackTrace,
      );
    } finally {
      // 후처리
      await testCase.teardown?.call(testData);
    }
  }
  
  /// CRUD 기능 생성
  test_models.TestableFeature _createCrudFeature(test_models.ScreenMetadata metadata) {
    return test_models.TestableFeature(
      featureName: 'CRUD Operations',
      type: test_models.FeatureType.crud,
      testCases: [
        test_models.TestCase(
          name: 'Create',
          execute: (data) async {
            // 생성 로직은 하위 클래스에서 구현
            await performCreate(data);
          },
          verify: (data) async {
            // 생성 검증 로직
            await verifyCreate(data);
          },
        ),
        test_models.TestCase(
          name: 'Read',
          execute: (data) async {
            await performRead(data);
          },
          verify: (data) async {
            await verifyRead(data);
          },
        ),
        test_models.TestCase(
          name: 'Update',
          execute: (data) async {
            await performUpdate(data);
          },
          verify: (data) async {
            await verifyUpdate(data);
          },
        ),
        test_models.TestCase(
          name: 'Delete',
          execute: (data) async {
            await performDelete(data);
          },
          verify: (data) async {
            await verifyDelete(data);
          },
        ),
      ],
      metadata: metadata.screenCapabilities['crud'] as Map<String, dynamic>,
    );
  }
  
  /// 검색 기능 생성
  test_models.TestableFeature _createSearchFeature(test_models.ScreenMetadata metadata) {
    return test_models.TestableFeature(
      featureName: 'Search',
      type: test_models.FeatureType.search,
      testCases: [
        test_models.TestCase(
          name: 'Search by keyword',
          execute: (data) async {
            await performSearch(data);
          },
          verify: (data) async {
            await verifySearch(data);
          },
        ),
      ],
      metadata: metadata.screenCapabilities['search'] as Map<String, dynamic>,
    );
  }
  
  /// 필터 기능 생성
  test_models.TestableFeature _createFilterFeature(test_models.ScreenMetadata metadata) {
    return test_models.TestableFeature(
      featureName: 'Filter',
      type: test_models.FeatureType.filter,
      testCases: [
        test_models.TestCase(
          name: 'Apply filters',
          execute: (data) async {
            await performFilter(data);
          },
          verify: (data) async {
            await verifyFilter(data);
          },
        ),
      ],
      metadata: metadata.screenCapabilities['filter'] as Map<String, dynamic>,
    );
  }
  
  /// 페이지네이션 기능 생성
  test_models.TestableFeature _createPaginationFeature(test_models.ScreenMetadata metadata) {
    return test_models.TestableFeature(
      featureName: 'Pagination',
      type: test_models.FeatureType.pagination,
      testCases: [
        test_models.TestCase(
          name: 'Navigate pages',
          execute: (data) async {
            await performPagination(data);
          },
          verify: (data) async {
            await verifyPagination(data);
          },
        ),
      ],
      metadata: metadata.screenCapabilities['pagination'] as Map<String, dynamic>,
    );
  }
  
  // 하위 클래스에서 구현해야 할 추상 메서드들
  Future<void> performCreate(test_models.TestData data);
  Future<void> verifyCreate(test_models.TestData data);
  Future<void> performRead(test_models.TestData data);
  Future<void> verifyRead(test_models.TestData data);
  Future<void> performUpdate(test_models.TestData data);
  Future<void> verifyUpdate(test_models.TestData data);
  Future<void> performDelete(test_models.TestData data);
  Future<void> verifyDelete(test_models.TestData data);
  Future<void> performSearch(test_models.TestData data);
  Future<void> verifySearch(test_models.TestData data);
  Future<void> performFilter(test_models.TestData data);
  Future<void> verifyFilter(test_models.TestData data);
  Future<void> performPagination(test_models.TestData data);
  Future<void> verifyPagination(test_models.TestData data);
}

/// 화면 테스트 프레임워크의 구체적인 구현
class ConcreteScreenTestFramework extends ScreenTestFramework {
  ConcreteScreenTestFramework({
    required super.testContext,
    required super.errorDiagnostics,
    required super.autoFixer,
    required super.dataGenerator,
    required super.reportCollector,
  });
  
  @override
  Future<List<test_models.TestableFeature>> detectCustomFeatures(test_models.ScreenMetadata metadata) async {
    // 화면별 커스텀 기능 감지 로직
    return [];
  }
  
  @override
  Future<void> performCreate(test_models.TestData data) async {
    // 구체적인 생성 로직 구현
  }
  
  @override
  Future<void> verifyCreate(test_models.TestData data) async {
    // 구체적인 생성 검증 로직 구현
  }
  
  @override
  Future<void> performRead(test_models.TestData data) async {
    // 구체적인 읽기 로직 구현
  }
  
  @override
  Future<void> verifyRead(test_models.TestData data) async {
    // 구체적인 읽기 검증 로직 구현
  }
  
  @override
  Future<void> performUpdate(test_models.TestData data) async {
    // 구체적인 수정 로직 구현
  }
  
  @override
  Future<void> verifyUpdate(test_models.TestData data) async {
    // 구체적인 수정 검증 로직 구현
  }
  
  @override
  Future<void> performDelete(test_models.TestData data) async {
    // 구체적인 삭제 로직 구현
  }
  
  @override
  Future<void> verifyDelete(test_models.TestData data) async {
    // 구체적인 삭제 검증 로직 구현
  }
  
  @override
  Future<void> performSearch(test_models.TestData data) async {
    // 구체적인 검색 로직 구현
  }
  
  @override
  Future<void> verifySearch(test_models.TestData data) async {
    // 구체적인 검색 검증 로직 구현
  }
  
  @override
  Future<void> performFilter(test_models.TestData data) async {
    // 구체적인 필터 로직 구현
  }
  
  @override
  Future<void> verifyFilter(test_models.TestData data) async {
    // 구체적인 필터 검증 로직 구현
  }
  
  @override
  Future<void> performPagination(test_models.TestData data) async {
    // 구체적인 페이지네이션 로직 구현
  }
  
  @override
  Future<void> verifyPagination(test_models.TestData data) async {
    // 구체적인 페이지네이션 검증 로직 구현
  }
}