import 'package:flutter_test/flutter_test.dart';
import 'package:get_it/get_it.dart';
import 'package:superport/data/datasources/remote/api_client.dart';
import 'package:superport/services/equipment_service.dart';
import 'package:superport/services/company_service.dart';
import 'package:superport/services/auth_service.dart';
import 'package:superport/data/models/auth/login_request.dart';
import 'package:superport/models/equipment_unified_model.dart';
import 'package:superport/screens/equipment/controllers/equipment_list_controller.dart';
// MockDataService는 제거됨
import '../real_api/test_helper.dart';

/// 체크박스 → 장비출고 인터랙티브 기능 테스트
/// 
/// 장비 목록에서 체크박스를 선택하고
/// 출고 프로세스를 테스트합니다.
class CheckboxEquipmentOutTest {
  final ApiClient apiClient;
  final GetIt getIt;
  
  late EquipmentService equipmentService;
  late CompanyService companyService;
  late AuthService authService;
  late EquipmentListController controller;
  
  // 테스트 결과
  final List<Map<String, dynamic>> testResults = [];
  
  CheckboxEquipmentOutTest({
    required this.apiClient,
    required this.getIt,
  });
  
  /// 서비스 초기화
  Future<void> initialize() async {
    print('\n${'=' * 60}');
    print('체크박스 → 장비출고 테스트 시작');
    print('${'=' * 60}\n');
    
    // 서비스 초기화
    equipmentService = getIt<EquipmentService>();
    companyService = getIt<CompanyService>();
    authService = getIt<AuthService>();
    
    // Controller 초기화 (MockDataService 제거됨)
    controller = EquipmentListController();
    
    // 인증
    await _ensureAuthenticated();
  }
  
  /// 인증 확인
  Future<void> _ensureAuthenticated() async {
    try {
      final isAuthenticated = await authService.isLoggedIn();
      
      if (!isAuthenticated) {
        print('로그인 시도...');
        final loginRequest = LoginRequest(
          email: 'admin@example.com',
          password: 'password123',
        );
        await authService.login(loginRequest);
        print('로그인 성공');
      }
    } catch (e) {
      print('인증 실패: $e');
      // throw e;
    }
  }
  
  /// 대량 장비 입고 헬퍼 함수
  Future<void> createBulkEquipmentIn(int count) async {
    print('\n대량 장비 입고 시작: $count개');
    
    final manufacturers = ['삼성전자', 'LG전자', 'Apple', '델', 'HP', '레노버'];
    final categories = ['노트북', '모니터', '서버', '프린터', '네트워크장비'];
    final subCategories = ['일반형', '고급형', '전문가용'];
    
    int successCount = 0;
    int failCount = 0;
    
    for (int i = 0; i < count; i++) {
      try {
        // 1. 장비 생성
        final equipment = Equipment(
          name: 'TEST-EQUIP-${DateTime.now().millisecondsSinceEpoch}-$i',
          serialNumber: 'SN-${DateTime.now().millisecondsSinceEpoch}-$i',
          manufacturer: manufacturers[i % manufacturers.length],
          category: categories[i % categories.length],
          subCategory: subCategories[i % subCategories.length],
          subSubCategory: '일반',
          inDate: DateTime.now(),
          quantity: 1,
        );
        
        final createdEquipment = await equipmentService.createEquipment(equipment);
        
        // 2. 장비 입고 처리
        if (createdEquipment.id != null) {
          await equipmentService.equipmentIn(
            equipmentId: createdEquipment.id!,
            quantity: 1,
            notes: '자동 테스트 입고 #$i',
          );
          successCount++;
          
          if ((i + 1) % 10 == 0) {
            print('  진행상황: ${i + 1}/$count 완료');
          }
        }
      } catch (e) {
        failCount++;
        print('  장비 #$i 입고 실패: $e');
      }
    }
    
    print('대량 장비 입고 완료: 성공 $successCount개, 실패 $failCount개');
  }
  
  /// 모든 테스트 실행
  Future<void> runAllTests() async {
    await initialize();
    
    // 1. 단일 선택 테스트
    await testSingleSelection();
    
    // 2. 다중 선택 테스트
    await testMultipleSelection();
    
    // 3. 전체 선택 테스트
    await testSelectAll();
    
    // 4. 상태별 필터링 후 선택 테스트
    await testFilteredSelection();
    
    // 5. 장비출고 프로세스 테스트
    await testEquipmentOutProcess();
    
    // 결과 출력
    _printTestResults();
  }
  
  /// 단일 선택 테스트
  Future<void> testSingleSelection() async {
    print('\n--- 단일 선택 테스트 ---');
    final result = <String, dynamic>{
      'test': '단일 선택',
      'steps': [],
    };
    
    try {
      // 장비 목록 로드
      await controller.loadData(isRefresh: true);
      result['steps'].add({
        'name': '장비 목록 로드',
        'status': 'PASS',
        'count': controller.equipments.length,
      });
      
      if (controller.equipments.isNotEmpty) {
        // 첫 번째 장비 선택
        final equipment = controller.equipments.first;
        controller.selectEquipment(equipment);
        
        final isSelected = controller.selectedEquipmentIds.contains('${equipment.id}:${equipment.status}');
        result['steps'].add({
          'name': '장비 선택',
          'status': isSelected ? 'PASS' : 'FAIL',
          'equipmentId': equipment.id,
          'selected': isSelected,
        });
        
        // 선택 해제
        controller.selectEquipment(equipment); // Toggle to deselect
        final isDeselected = !controller.selectedEquipmentIds.contains('${equipment.id}:${equipment.status}');
        result['steps'].add({
          'name': '장비 선택 해제',
          'status': isDeselected ? 'PASS' : 'FAIL',
          'deselected': isDeselected,
        });
      }
      
      result['overall'] = 'PASS';
    } catch (e) {
      result['overall'] = 'FAIL';
      result['error'] = e.toString();
    }
    
    testResults.add(result);
  }
  
  /// 다중 선택 테스트
  Future<void> testMultipleSelection() async {
    print('\n--- 다중 선택 테스트 ---');
    final result = <String, dynamic>{
      'test': '다중 선택',
      'steps': [],
    };
    
    try {
      await controller.loadData(isRefresh: true);
      
      if (controller.equipments.length >= 3) {
        // 상위 3개 장비 선택
        final equipmentsToSelect = controller.equipments.take(3).toList();
        
        for (final equipment in equipmentsToSelect) {
          controller.selectEquipment(equipment);
        }
        
        final selectedCount = controller.getSelectedEquipmentCount();
        result['steps'].add({
          'name': '3개 장비 선택',
          'status': selectedCount == 3 ? 'PASS' : 'FAIL',
          'expectedCount': 3,
          'actualCount': selectedCount,
        });
        
        // 선택된 장비 목록 확인
        final selectedEquipments = controller.getSelectedEquipments();
        result['steps'].add({
          'name': '선택된 장비 목록 확인',
          'status': selectedEquipments.length == 3 ? 'PASS' : 'FAIL',
          'selectedIds': selectedEquipments.map((e) => e.id).toList(),
        });
      }
      
      result['overall'] = 'PASS';
    } catch (e) {
      result['overall'] = 'FAIL';
      result['error'] = e.toString();
    }
    
    testResults.add(result);
  }
  
  /// 전체 선택 테스트
  Future<void> testSelectAll() async {
    print('\n--- 전체 선택 테스트 ---');
    final result = <String, dynamic>{
      'test': '전체 선택',
      'steps': [],
    };
    
    try {
      await controller.loadData(isRefresh: true);
      
      // 전체 선택 시뮬레이션
      for (final equipment in controller.equipments) {
        controller.selectEquipment(equipment);
      }
      
      final selectedCount = controller.getSelectedEquipmentCount();
      final totalCount = controller.equipments.length;
      
      result['steps'].add({
        'name': '전체 선택',
        'status': selectedCount == totalCount ? 'PASS' : 'FAIL',
        'totalCount': totalCount,
        'selectedCount': selectedCount,
      });
      
      // 전체 해제
      for (final equipment in controller.equipments) {
        controller.selectEquipment(equipment); // Toggle to deselect
      }
      
      final afterDeselectCount = controller.getSelectedEquipmentCount();
      result['steps'].add({
        'name': '전체 선택 해제',
        'status': afterDeselectCount == 0 ? 'PASS' : 'FAIL',
        'remainingCount': afterDeselectCount,
      });
      
      result['overall'] = 'PASS';
    } catch (e) {
      result['overall'] = 'FAIL';
      result['error'] = e.toString();
    }
    
    testResults.add(result);
  }
  
  /// 상태별 필터링 후 선택 테스트
  Future<void> testFilteredSelection() async {
    print('\n--- 상태별 필터링 후 선택 테스트 ---');
    final result = <String, dynamic>{
      'test': '필터링 후 선택',
      'steps': [],
    };
    
    try {
      // 입고 상태 필터 적용
      controller.changeStatusFilter('available');
      
      result['steps'].add({
        'name': '입고 상태 필터 적용',
        'status': 'PASS',
        'filter': 'available',
        'count': controller.equipments.length,
      });
      
      // 필터링된 장비 중 선택
      if (controller.equipments.isNotEmpty) {
        final availableEquipments = controller.equipments
            .where((e) => e.status == 'available')
            .take(2)
            .toList();
        
        for (final equipment in availableEquipments) {
          controller.selectEquipment(equipment);
        }
        
        final selectedInStockCount = controller.getSelectedEquipmentCountByStatus('available');
        result['steps'].add({
          'name': '입고 장비만 선택',
          'status': selectedInStockCount > 0 ? 'PASS' : 'FAIL',
          'selectedCount': selectedInStockCount,
        });
      }
      
      result['overall'] = 'PASS';
    } catch (e) {
      result['overall'] = 'FAIL';
      result['error'] = e.toString();
    }
    
    testResults.add(result);
  }
  
  /// 장비출고 프로세스 테스트
  Future<void> testEquipmentOutProcess() async {
    print('\n--- 장비출고 프로세스 테스트 ---');
    final result = <String, dynamic>{
      'test': '장비출고 프로세스',
      'steps': [],
    };
    
    try {
      // 기존 장비 활용 (이미 available 상태 장비가 충분히 있음)
      print('\n출고 테스트 시작...');
      
      // 1. 입고 상태 장비 로드
      await controller.loadData(isRefresh: true);
      controller.changeStatusFilter('available');
      
      final availableCount = controller.equipments
          .where((e) => e.status == 'available')
          .length;
      
      result['steps'].add({
        'name': '입고 상태 장비 확인',
        'status': availableCount > 0 ? 'PASS' : 'FAIL',
        'availableCount': availableCount,
      });
      
      if (availableCount > 0) {
        // 2. 단일 장비 출고
        final singleEquipment = controller.equipments
            .where((e) => e.status == 'available')
            .first;
        
        controller.selectEquipment(singleEquipment);
        
        result['steps'].add({
          'name': '단일 장비 선택',
          'status': 'PASS',
          'equipmentId': singleEquipment.id,
        });
        
        // 회사 목록 조회 (출고 대상)
        final companies = await companyService.getCompanies(page: 1, perPage: 5);
        if (companies.items.isNotEmpty) {
          final targetCompany = companies.items.first;
          
          try {
            // 단일 출고 처리
            await equipmentService.equipmentOut(
              equipmentId: singleEquipment.id!,
              quantity: 1,
              companyId: targetCompany.id!,
              notes: '자동 테스트 - 단일 출고',
            );
            result['steps'].add({
              'name': '단일 장비 출고 처리',
              'status': 'PASS',
              'companyId': targetCompany.id,
            });
          } catch (e) {
            result['steps'].add({
              'name': '단일 장비 출고 처리',
              'status': 'FAIL',
              'error': e.toString(),
            });
          }
          
          // 3. 다중 장비 출고 (10개)
          controller.selectedEquipmentIds.clear(); // 선택 초기화
          await controller.loadData(isRefresh: true); // 목록 새로고침
          
          final multipleEquipments = controller.equipments
              .where((e) => e.status == 'available')
              .take(10)
              .toList();
          
          if (multipleEquipments.length >= 10) {
            int outSuccessCount = 0;
            int outFailCount = 0;
            
            for (final equipment in multipleEquipments) {
              try {
                await equipmentService.equipmentOut(
                  equipmentId: equipment.id!,
                  quantity: 1,
                  companyId: targetCompany.id!,
                  notes: '자동 테스트 - 대량 출고',
                );
                outSuccessCount++;
              } catch (e) {
                outFailCount++;
              }
            }
            
            result['steps'].add({
              'name': '대량 장비 출고 (10개)',
              'status': outSuccessCount >= 8 ? 'PASS' : 'FAIL',
              'successCount': outSuccessCount,
              'failCount': outFailCount,
            });
          }
          
          // 4. 출고 후 상태 확인
          await controller.loadData(isRefresh: true);
          controller.changeStatusFilter('inuse');
          
          final inUseCount = controller.equipments
              .where((e) => e.status == 'inuse')
              .length;
          
          result['steps'].add({
            'name': '출고 후 상태 변경 확인',
            'status': inUseCount > 0 ? 'PASS' : 'FAIL',
            'inUseCount': inUseCount,
          });
          
        } else {
          result['steps'].add({
            'name': '출고 대상 회사 조회',
            'status': 'FAIL',
            'note': '회사 목록이 비어있음',
          });
        }
      } else {
        result['steps'].add({
          'name': '출고 가능 장비 확인',
          'status': 'FAIL',
          'note': '입고 상태 장비가 없음',
        });
      }
      
      result['overall'] = result['steps'].every((s) => s['status'] == 'PASS') ? 'PASS' : 'PARTIAL';
    } catch (e) {
      result['overall'] = 'FAIL';
      result['error'] = e.toString();
    }
    
    testResults.add(result);
  }
  
  /// 테스트 결과 출력
  void _printTestResults() {
    print('\n${'=' * 60}');
    print('체크박스 → 장비출고 테스트 결과');
    print('${'=' * 60}\n');
    
    for (final result in testResults) {
      print('테스트: ${result['test']}');
      print('결과: ${result['overall']}');
      
      if (result['steps'] != null) {
        for (final step in result['steps']) {
          print('  - ${step['name']}: ${step['status']}');
          if (step['error'] != null) {
            print('    에러: ${step['error']}');
          }
          if (step['note'] != null) {
            print('    참고: ${step['note']}');
          }
        }
      }
      
      print('');
    }
    
    // 요약
    final passedCount = testResults.where((r) => r['overall'] == 'PASS').length;
    final failedCount = testResults.where((r) => r['overall'] == 'FAIL').length;
    final partialCount = testResults.where((r) => r['overall'] == 'PARTIAL').length;
    
    print('테스트 요약:');
    print('  성공: $passedCount');
    print('  실패: $failedCount');
    print('  부분 성공: $partialCount');
  }
}

/// 테스트 실행
const bool RUN_EXTERNAL_TESTS = bool.fromEnvironment('RUN_EXTERNAL_TESTS');
void main() async {
  if (!RUN_EXTERNAL_TESTS) {
    test('External tests disabled', () {}, skip: 'Enable with --dart-define=RUN_EXTERNAL_TESTS=true');
    return;
  }
  // 실제 API 환경 설정
  await RealApiTestHelper.setupTestEnvironment();
  final getIt = GetIt.instance;
  
  group('체크박스 → 장비출고 테스트', () {
    setUpAll(() async {
      // 로그인 및 토큰 설정
      await RealApiTestHelper.loginAndGetToken();
    });
    
    tearDownAll(() async {
      await RealApiTestHelper.teardownTestEnvironment();
    });
    
    test('체크박스 선택 및 장비출고 프로세스', () async {
      final tester = CheckboxEquipmentOutTest(
        apiClient: getIt.get<ApiClient>(),
        getIt: getIt,
      );
      
      await tester.runAllTests();
    }, timeout: Timeout(Duration(minutes: 5)));
  });
}
