import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:superport/services/equipment_service.dart';
import 'package:superport/models/equipment_unified_model.dart';
import 'base_screen_test.dart';
import '../../framework/models/test_models.dart';

/// BaseScreenTest를 상속받아 구현하는 예제
/// 
/// 이 예제는 Equipment 화면 테스트를 구현하는 방법을 보여줍니다.
/// 다른 화면들도 이와 유사한 방식으로 구현할 수 있습니다.
class ExampleEquipmentScreenTest extends BaseScreenTest {
  late EquipmentService equipmentService;
  
  ExampleEquipmentScreenTest({
    required super.apiClient,
    required super.getIt,
    required super.testContext,
    required super.errorDiagnostics,
    required super.autoFixer,
    required super.dataGenerator,
    required super.reportCollector,
  });
  
  // ===== 필수 구현 메서드들 =====
  
  @override
  ScreenMetadata getScreenMetadata() {
    return ScreenMetadata(
      screenName: 'EquipmentListScreen',
      controllerType: EquipmentService,
      relatedEndpoints: [
        ApiEndpoint(
          path: '/api/v1/equipment',
          method: 'GET',
          description: '장비 목록 조회',
        ),
        ApiEndpoint(
          path: '/api/v1/equipment',
          method: 'POST',
          description: '장비 생성',
        ),
        ApiEndpoint(
          path: '/api/v1/equipment/{id}',
          method: 'PUT',
          description: '장비 수정',
        ),
        ApiEndpoint(
          path: '/api/v1/equipment/{id}',
          method: 'DELETE',
          description: '장비 삭제',
        ),
      ],
      screenCapabilities: {
        'crud': {
          'create': true,
          'read': true,
          'update': true,
          'delete': true,
        },
        'search': {
          'enabled': true,
          'fields': ['name', 'serialNumber', 'manufacturer'],
        },
        'filter': {
          'enabled': true,
          'fields': ['status', 'category', 'location'],
        },
        'pagination': {
          'enabled': true,
          'defaultPerPage': 20,
        },
      },
    );
  }
  
  @override
  Future<void> initializeServices() async {
    equipmentService = getIt<EquipmentService>();
  }
  
  @override
  dynamic getService() => equipmentService;
  
  @override
  String getResourceType() => 'equipment';
  
  @override
  Map<String, dynamic> getDefaultFilters() {
    return {
      'status': 'active',
      'category': 'all',
    };
  }
  
  // ===== CRUD 작업 구현 =====
  
  @override
  Future<dynamic> performCreateOperation(TestData data) async {
    // TestData에서 Equipment 객체로 변환
    final equipmentData = data.data;
    final equipment = Equipment(
      manufacturer: equipmentData['manufacturer'] ?? 'Unknown',
      name: equipmentData['name'] ?? 'Test Equipment',
      category: equipmentData['category'] ?? '미분류',
      subCategory: equipmentData['subCategory'] ?? '',
      subSubCategory: equipmentData['subSubCategory'] ?? '',
      serialNumber: equipmentData['serialNumber'] ?? 'SN-${DateTime.now().millisecondsSinceEpoch}',
      quantity: equipmentData['quantity'] ?? 1,
      inDate: equipmentData['inDate'] ?? DateTime.now().toIso8601String(),
      remark: equipmentData['remark'],
    );
    
    return await equipmentService.createEquipment(equipment);
  }
  
  @override
  Future<dynamic> performReadOperation(TestData data) async {
    // 페이지네이션 파라미터 사용
    final page = data.data['page'] ?? 1;
    final perPage = data.data['perPage'] ?? 20;
    
    return await equipmentService.getEquipments(
      page: page,
      perPage: perPage,
    );
  }
  
  @override
  Future<dynamic> performUpdateOperation(dynamic resourceId, Map<String, dynamic> updateData) async {
    // 기존 장비 조회
    final existing = await equipmentService.getEquipment(resourceId);
    
    // 업데이트할 Equipment 객체 생성
    final updated = Equipment(
      id: existing.id,
      manufacturer: updateData['manufacturer'] ?? existing.manufacturer,
      name: updateData['name'] ?? existing.name,
      category: updateData['category'] ?? existing.category,
      subCategory: updateData['subCategory'] ?? existing.subCategory,
      subSubCategory: updateData['subSubCategory'] ?? existing.subSubCategory,
      serialNumber: updateData['serialNumber'] ?? existing.serialNumber,
      quantity: updateData['quantity'] ?? existing.quantity,
      inDate: updateData['inDate'] ?? existing.inDate,
      remark: updateData['remark'] ?? existing.remark,
    );
    
    return await equipmentService.updateEquipment(resourceId, updated);
  }
  
  @override
  Future<void> performDeleteOperation(dynamic resourceId) async {
    await equipmentService.deleteEquipment(resourceId);
  }
  
  @override
  dynamic extractResourceId(dynamic resource) {
    if (resource is Equipment) {
      return resource.id;
    }
    return resource['id'] ?? resource.id;
  }
  
  // ===== 선택적 구현 메서드들 (필요시 오버라이드) =====
  
  @override
  Future<void> validateDataBeforeCreate(TestData data) async {
    // 장비 생성 전 데이터 검증
    final equipmentData = data.data;
    
    // 필수 필드 검증
    if (equipmentData['manufacturer'] == null || equipmentData['manufacturer'].isEmpty) {
      throw ValidationError('제조사는 필수 입력 항목입니다');
    }
    
    if (equipmentData['name'] == null || equipmentData['name'].isEmpty) {
      throw ValidationError('장비명은 필수 입력 항목입니다');
    }
    
    // 시리얼 번호 형식 검증
    final serialNumber = equipmentData['serialNumber'];
    if (serialNumber != null && !RegExp(r'^[A-Z0-9\-]+$').hasMatch(serialNumber)) {
      throw ValidationError('시리얼 번호는 영문 대문자, 숫자, 하이픈만 사용 가능합니다');
    }
  }
  
  @override
  Future<Map<String, dynamic>> prepareUpdateData(TestData data, dynamic resourceId) async {
    // 기본 구현에 추가로 장비별 특수 로직 적용
    final updateData = await super.prepareUpdateData(data, resourceId);
    
    // 장비 상태 업데이트 시 이력 추가
    if (updateData.containsKey('status')) {
      updateData['statusChangeReason'] = '테스트 상태 변경';
      updateData['statusChangedAt'] = DateTime.now().toIso8601String();
    }
    
    return updateData;
  }
  
  @override
  Future<void> performAdditionalSetup() async {
    // 장비 테스트를 위한 추가 설정
    _log('장비 테스트용 카테고리 마스터 데이터 확인');
    
    // 필요한 경우 카테고리 마스터 데이터 생성
    // await _ensureCategoryMasterData();
  }
  
  @override
  Future<void> performAdditionalCleanup() async {
    // 장비 테스트 후 추가 정리
    _log('장비 관련 임시 파일 정리');
    
    // 테스트 중 생성된 임시 파일이나 캐시 정리
    // await _cleanupTempFiles();
  }
  
  // ===== 커스텀 기능 테스트 =====
  
  @override
  Future<List<TestableFeature>> detectCustomFeatures(ScreenMetadata metadata) async {
    final features = <TestableFeature>[];
    
    // 장비 입출고 기능 테스트
    features.add(TestableFeature(
      featureName: 'Equipment In/Out',
      type: FeatureType.custom,
      testCases: [
        TestCase(
          name: 'Equipment check-in',
          execute: (data) async {
            await performEquipmentCheckIn(data);
          },
          verify: (data) async {
            await verifyEquipmentCheckIn(data);
          },
        ),
        TestCase(
          name: 'Equipment check-out',
          execute: (data) async {
            await performEquipmentCheckOut(data);
          },
          verify: (data) async {
            await verifyEquipmentCheckOut(data);
          },
        ),
      ],
      metadata: {
        'description': '장비 입출고 프로세스 테스트',
      },
    ));
    
    // 장비 이력 조회 기능 테스트
    features.add(TestableFeature(
      featureName: 'Equipment History',
      type: FeatureType.custom,
      testCases: [
        TestCase(
          name: 'View equipment history',
          execute: (data) async {
            await performViewHistory(data);
          },
          verify: (data) async {
            await verifyViewHistory(data);
          },
        ),
      ],
      metadata: {
        'description': '장비 이력 조회 테스트',
      },
    ));
    
    return features;
  }
  
  // 장비 입고 테스트
  Future<void> performEquipmentCheckIn(TestData data) async {
    // 먼저 장비 생성
    await performCreate(data);
    final equipmentId = testContext.getData('lastCreatedId');
    
    // 입고 처리
    final checkInResult = await equipmentService.equipmentIn(
      equipmentId: equipmentId,
      quantity: 1,
      warehouseLocationId: testContext.getData('testWarehouseId') ?? 1,
      notes: '테스트 입고',
    );
    
    testContext.setData('checkInResult', checkInResult);
  }
  
  Future<void> verifyEquipmentCheckIn(TestData data) async {
    final checkInResult = testContext.getData('checkInResult');
    expect(checkInResult, isNotNull, reason: '장비 입고 실패');
    expect(checkInResult.success, isTrue, reason: '입고 처리가 성공하지 못했습니다');
  }
  
  // 장비 출고 테스트
  Future<void> performEquipmentCheckOut(TestData data) async {
    // 입고된 장비가 있는지 확인
    final equipmentId = testContext.getData('lastCreatedId');
    if (equipmentId == null) {
      await performEquipmentCheckIn(data);
    }
    
    // 출고 처리
    final checkOutResult = await equipmentService.equipmentOut(
      equipmentId: equipmentId,
      quantity: 1,
      companyId: testContext.getData('testCompanyId') ?? 1,
      notes: '테스트 출고',
    );
    
    testContext.setData('checkOutResult', checkOutResult);
  }
  
  Future<void> verifyEquipmentCheckOut(TestData data) async {
    final checkOutResult = testContext.getData('checkOutResult');
    expect(checkOutResult, isNotNull, reason: '장비 출고 실패');
    expect(checkOutResult.success, isTrue, reason: '출고 처리가 성공하지 못했습니다');
  }
  
  // 장비 이력 조회 테스트
  Future<void> performViewHistory(TestData data) async {
    final equipmentId = testContext.getData('lastCreatedId');
    if (equipmentId == null) {
      await performCreate(data);
    }
    
    final history = await equipmentService.getEquipmentHistory(equipmentId);
    testContext.setData('equipmentHistory', history);
  }
  
  Future<void> verifyViewHistory(TestData data) async {
    final history = testContext.getData('equipmentHistory');
    expect(history, isNotNull, reason: '장비 이력 조회 실패');
    expect(history, isA<List>(), reason: '이력이 리스트 형식이 아닙니다');
  }
  
  // 로깅을 위한 헬퍼 메서드
  void _log(String message) {
    debugPrint('[ExampleEquipmentScreenTest] $message');
  }
}

/// 검증 오류
class ValidationError implements Exception {
  final String message;
  
  ValidationError(this.message);
  
  @override
  String toString() => 'ValidationError: $message';
}

// 테스트 실행 예제
void main() {
  group('Example Equipment Screen Test', () {
    test('BaseScreenTest를 상속받아 구현하는 방법 예제', () {
      // 이것은 예제 구현입니다.
      // 실제 테스트는 프레임워크를 통해 실행됩니다.
      expect(true, isTrue);
    });
  });
}