import 'package:dio/dio.dart';
import 'package:get_it/get_it.dart';
import 'package:superport/data/datasources/remote/api_client.dart';
import 'api_error_diagnostics.dart';
import 'auto_fixer.dart';
import 'test_data_generator.dart';
import 'test_auth_service.dart';
import '../models/error_models.dart';
import '../infrastructure/report_collector.dart';

/// 자동 테스트 및 수정 시스템
/// 
/// 화면별로 모든 기능을 자동으로 테스트하고,
/// 에러 발생 시 자동으로 수정하는 시스템
class AutoTestSystem {
  final ApiClient apiClient;
  final GetIt getIt;
  final ApiErrorDiagnostics errorDiagnostics;
  final ApiAutoFixer autoFixer;
  final TestDataGenerator dataGenerator;
  final ReportCollector reportCollector;
  late TestAuthService _testAuthService;
  
  static const String _testEmail = 'admin@superport.kr';
  static const String _testPassword = 'admin123!';
  
  bool _isLoggedIn = false;
  String? _accessToken;
  
  AutoTestSystem({
    required this.apiClient,
    required this.getIt,
    required this.errorDiagnostics,
    required this.autoFixer,
    required this.dataGenerator,
    required this.reportCollector,
  }) {
    _testAuthService = TestAuthHelper.getInstance(apiClient);
  }
  
  /// 테스트 시작 전 로그인
  Future<void> ensureAuthenticated() async {
    if (_isLoggedIn && _accessToken != null) {
      return;
    }
    
    // debugPrint('[AutoTestSystem] 인증 시작...');
    
    try {
      final loginResponse = await _testAuthService.login(_testEmail, _testPassword);
      
      _accessToken = loginResponse.accessToken;
      _isLoggedIn = true;
      
      // debugPrint('[AutoTestSystem] 로그인 성공!');
      // debugPrint('[AutoTestSystem] 사용자: ${loginResponse.user.email}');
      // debugPrint('[AutoTestSystem] 역할: ${loginResponse.user.role}');
    } catch (e) {
      // debugPrint('[AutoTestSystem] 로그인 에러: $e');
      throw Exception('인증 실패: $e');
    }
  }
  
  /// 테스트 실행 및 자동 수정
  Future<TestResult> runTestWithAutoFix({
    required String testName,
    required String screenName,
    required Future<void> Function() testFunction,
    int maxRetries = 3,
  }) async {
    // debugPrint('\n[AutoTestSystem] 테스트 시작: $testName');
    
    // 인증 확인
    await ensureAuthenticated();
    
    int retryCount = 0;
    Exception? lastError;
    
    while (retryCount < maxRetries) {
      try {
        // 테스트 실행
        await testFunction();
        
        // debugPrint('[AutoTestSystem] ✅ 테스트 성공: $testName');
        
        // 성공 리포트
        reportCollector.addTestResult(
          screenName: screenName,
          testName: testName,
          passed: true,
        );
        
        return TestResult(
          testName: testName,
          passed: true,
          retryCount: retryCount,
        );
      } catch (e) {
        // Exception이나 AssertionError 모두 처리
        if (e is Exception) {
          lastError = e;
        } else if (e is AssertionError) {
          lastError = Exception('Assertion failed: ${e.message}');
        } else {
          lastError = Exception('Test failed: $e');
        }
        retryCount++;
        
        // debugPrint('[AutoTestSystem] ❌ 테스트 실패 (시도 $retryCount/$maxRetries): $e');
        
        // 에러 분석 및 수정 시도
        if (retryCount < maxRetries) {
          final fixed = await _tryAutoFix(testName, screenName, e);
          
          if (!fixed) {
            break; // 수정 불가능한 에러
          }
          
          // 재시도 전 대기
          await Future.delayed(Duration(seconds: 1));
        }
      }
    }
    
    // 실패 리포트
    reportCollector.addTestResult(
      screenName: screenName,
      testName: testName,
      passed: false,
      error: lastError.toString(),
    );
    
    return TestResult(
      testName: testName,
      passed: false,
      error: lastError?.toString(),
      retryCount: retryCount,
    );
  }
  
  /// 에러 자동 수정 시도
  Future<bool> _tryAutoFix(String testName, String screenName, dynamic error) async {
    // debugPrint('[AutoTestSystem] 자동 수정 시도 중...');
    
    try {
      if (error is DioException) {
        // API 에러를 ApiError로 변환
        final apiError = ApiError(
          statusCode: error.response?.statusCode,
          requestUrl: error.requestOptions.uri.toString(),
          requestMethod: error.requestOptions.method,
          requestBody: error.requestOptions.data,
          responseBody: error.response?.data,
          originalError: error,
          timestamp: DateTime.now(),
        );
        
        // API 에러 진단
        final diagnosis = await errorDiagnostics.diagnose(apiError);
        
        switch (diagnosis.type) {
          case ApiErrorType.authentication:
            // 인증 에러 - 재로그인
            // debugPrint('[AutoTestSystem] 인증 에러 감지 - 재로그인 시도');
            _isLoggedIn = false;
            _accessToken = null;
            await ensureAuthenticated();
            return true;
            
          case ApiErrorType.validation:
            // 검증 에러 - 데이터 수정
            // debugPrint('[AutoTestSystem] 검증 에러 감지 - 데이터 수정 시도');
            final validationErrors = _extractValidationErrors(error);
            if (validationErrors.isNotEmpty) {
              // debugPrint('[AutoTestSystem] 검증 에러 필드: ${validationErrors.keys.join(', ')}');
              // 여기서 데이터 수정 로직 구현
              return true;
            }
            return false;
            
          case ApiErrorType.notFound:
            // 리소스 없음 - 생성 필요
            // debugPrint('[AutoTestSystem] 리소스 없음 - 생성 시도');
            // 여기서 필요한 리소스 생성 로직 구현
            return true;
            
          case ApiErrorType.serverError:
            // 서버 에러 - 재시도
            // debugPrint('[AutoTestSystem] 서버 에러 - 재시도 대기');
            await Future.delayed(Duration(seconds: 2));
            return true;
            
          default:
            // debugPrint('[AutoTestSystem] 수정 불가능한 에러: ${diagnosis.type}');
            return false;
        }
      } else if (error.toString().contains('필수')) {
        // 필수 필드 누락 에러
        // debugPrint('[AutoTestSystem] 필수 필드 누락 - 기본값 생성');
        return true;
      }
      
      return false;
    } catch (e) {
      // debugPrint('[AutoTestSystem] 자동 수정 실패: $e');
      return false;
    }
  }
  
  /// 검증 에러 추출
  Map<String, List<String>> _extractValidationErrors(DioException error) {
    try {
      final responseData = error.response?.data;
      if (responseData is Map && responseData['errors'] is Map) {
        return Map<String, List<String>>.from(
          responseData['errors'].map((key, value) => MapEntry(
            key.toString(),
            value is List ? value.map((e) => e.toString()).toList() : [value.toString()],
          )),
        );
      }
    } catch (_) {}
    return {};
  }
  
  /// 테스트 데이터 자동 생성
  Future<Map<String, dynamic>> generateTestData(String dataType) async {
    switch (dataType) {
      case 'equipment':
        return await _generateEquipmentData();
      case 'company':
        return await _generateCompanyData();
      case 'warehouse':
        return await _generateWarehouseData();
      case 'user':
        return await _generateUserData();
      case 'license':
        return await _generateLicenseData();
      default:
        return {};
    }
  }
  
  Future<Map<String, dynamic>> _generateEquipmentData() async {
    final serialNumber = dataGenerator.generateSerialNumber();
    return {
      'equipment_number': 'EQ-${dataGenerator.generateId()}', // 필수 필드
      'serial_number': serialNumber,
      'manufacturer': dataGenerator.generateCompanyName(),
      'model_name': dataGenerator.generateEquipmentName(), // model_name으로 변경
      'status': 'available',
      'category': 'Material Handling',
      'current_company_id': 1, // current_company_id로 변경
      'warehouse_location_id': 1, // 실제 창고 ID로 교체 필요
      'purchase_date': DateTime.now().toIso8601String().split('T')[0],
      'purchase_price': dataGenerator.generatePrice(),
    };
  }
  
  Future<Map<String, dynamic>> _generateCompanyData() async {
    return {
      'name': dataGenerator.generateCompanyName(),
      'code': 'COMP-${dataGenerator.generateId()}',
      'business_type': 'Manufacturing',
      'registration_number': TestDataGenerator.generateBusinessNumber(),
      'representative_name': dataGenerator.generatePersonName(),
      'phone': TestDataGenerator.generatePhoneNumber(),
      'email': dataGenerator.generateEmail(),
      'is_active': true,
    };
  }
  
  Future<Map<String, dynamic>> _generateWarehouseData() async {
    return {
      'name': 'Warehouse ${dataGenerator.generateId()}',
      'code': 'WH-${dataGenerator.generateId()}',
      'address_line1': dataGenerator.generateAddress(),
      'city': '서울시',
      'state_province': '서울',
      'postal_code': dataGenerator.generatePostalCode(),
      'country': 'Korea',
      'capacity': 10000,
      'manager_name': dataGenerator.generatePersonName(),
      'contact_phone': TestDataGenerator.generatePhoneNumber(),
      'is_active': true,
    };
  }
  
  Future<Map<String, dynamic>> _generateUserData() async {
    return {
      'email': dataGenerator.generateEmail(),
      'username': dataGenerator.generateUsername(),
      'password': 'Test1234!',
      'first_name': dataGenerator.generatePersonName().split(' ')[0],
      'last_name': dataGenerator.generatePersonName().split(' ')[1],
      'role': 'staff',
      'company_id': 1, // 실제 회사 ID로 교체 필요
      'department': 'IT',
      'phone': TestDataGenerator.generatePhoneNumber(),
    };
  }
  
  Future<Map<String, dynamic>> _generateLicenseData() async {
    return {
      'license_key': dataGenerator.generateLicenseKey(),
      'software_name': dataGenerator.generateSoftwareName(),
      'license_type': 'subscription',
      'seats': 10,
      'company_id': 1, // 실제 회사 ID로 교체 필요
      'purchase_date': DateTime.now().toIso8601String().split('T')[0],
      'expiry_date': DateTime.now().add(Duration(days: 365)).toIso8601String().split('T')[0],
      'cost': dataGenerator.generatePrice(),
      'vendor': dataGenerator.generateCompanyName(),
      'is_active': true,
    };
  }
}

/// 테스트 결과
class TestResult {
  final String testName;
  final bool passed;
  final String? error;
  final int retryCount;
  
  TestResult({
    required this.testName,
    required this.passed,
    this.error,
    this.retryCount = 0,
  });
}