import 'package:dio/dio.dart';
import 'package:get_it/get_it.dart';
import 'package:superport/core/constants/api_endpoints.dart';
import 'package:superport/core/errors/exceptions.dart';
import 'package:superport/data/datasources/remote/api_client.dart';
import 'package:superport/data/models/equipment/equipment_dto.dart';

abstract class EquipmentRemoteDataSource {
  Future<EquipmentListResponse> getEquipments({
    int page = 1,
    int perPage = 20,
    String? search,
    int? companyId,
  });
  
  Future<EquipmentDto> createEquipment(EquipmentRequestDto request);
  
  Future<EquipmentDto> getEquipmentDetail(int id);
  
  Future<EquipmentDto> updateEquipment(int id, EquipmentUpdateRequestDto request);
  
  Future<void> deleteEquipment(int id);

  Future<EquipmentDto> restoreEquipment(int id);

  Future<EquipmentDto> getEquipmentBySerial(String serial);

  Future<EquipmentDto> getEquipmentByBarcode(String barcode);

  Future<List<EquipmentDto>> getEquipmentsByCompany(int companyId);
}

class EquipmentRemoteDataSourceImpl implements EquipmentRemoteDataSource {
  final ApiClient _apiClient = GetIt.instance<ApiClient>();

  /// DioException을 ServerException으로 변환하는 헬퍼 메서드
  Never _handleDioException(DioException e) {
    String errorMessage = 'Network error occurred';
    
    if (e.response?.data != null) {
      // 응답 데이터가 Map인 경우 (JSON 에러)
      if (e.response!.data is Map<String, dynamic>) {
        final errorData = e.response!.data as Map<String, dynamic>;
        errorMessage = errorData['error']?['message'] ?? 
                      errorData['message'] ?? 
                      'Server error occurred';
      } 
      // 응답 데이터가 String인 경우 (Plain text 에러)
      else if (e.response!.data is String) {
        errorMessage = e.response!.data as String;
      }
    }
    
    throw ServerException(
      message: errorMessage,
      statusCode: e.response?.statusCode,
    );
  }

  @override
  Future<EquipmentListResponse> getEquipments({
    int page = 1,
    int perPage = 20,
    String? search,
    int? companyId,
  }) async {
    try {
      final queryParams = <String, dynamic>{
        'page': page,
        'page_size': perPage,
        if (search != null && search.isNotEmpty) 'search': search,
        if (companyId != null) 'company_id': companyId,
      };

      final response = await _apiClient.get(
        ApiEndpoints.equipment,
        queryParameters: queryParams,
      );

      print('[Equipment API] Response: ${response.data}');

      // 백엔드 응답은 직접 data 배열과 페이지네이션 정보 반환
      final Map<String, dynamic> responseData = response.data;
      return EquipmentListResponse.fromJson(responseData);
    } on DioException catch (e) {
      _handleDioException(e);
    }
  }

  @override
  Future<EquipmentDto> createEquipment(EquipmentRequestDto request) async {
    try {
      final response = await _apiClient.post(
        ApiEndpoints.equipment,
        data: request.toJson(),
      );

      print('[Equipment API] Create Response: ${response.data}');
      
      // API 응답이 {success: true, data: {...}} 형태인 경우 처리
      final responseData = response.data;
      if (responseData is Map && responseData.containsKey('data')) {
        return EquipmentDto.fromJson(responseData['data']);
      } else {
        // 직접 데이터인 경우
        return EquipmentDto.fromJson(responseData);
      }
    } on DioException catch (e) {
      _handleDioException(e);
    }
  }

  @override
  Future<EquipmentDto> getEquipmentDetail(int id) async {
    try {
      final response = await _apiClient.get('${ApiEndpoints.equipment}/$id');

      print('[Equipment API] Detail Response: ${response.data}');
      
      // API 응답이 {success: true, data: {...}} 형태인 경우 처리
      final responseData = response.data;
      if (responseData is Map && responseData.containsKey('data')) {
        return EquipmentDto.fromJson(responseData['data']);
      } else {
        // 직접 데이터인 경우
        return EquipmentDto.fromJson(responseData);
      }
    } on DioException catch (e) {
      _handleDioException(e);
    }
  }

  @override
  Future<EquipmentDto> updateEquipment(int id, EquipmentUpdateRequestDto request) async {
    try {
      // 디버그: 전송할 JSON 데이터 로깅
      final jsonData = request.toJson();
      
      // null 필드 제거 (백엔드가 null을 처리하지 못하는 경우 대비)
      final cleanedData = Map<String, dynamic>.from(jsonData)
        ..removeWhere((key, value) => value == null);
      
      print('[Equipment API] Update Request JSON: $cleanedData');
      print('[Equipment API] JSON keys: ${cleanedData.keys.toList()}');
      
      final response = await _apiClient.put(
        '${ApiEndpoints.equipment}/$id',
        data: cleanedData,
      );

      print('[Equipment API] Update Response: ${response.data}');
      
      // API 응답이 {success: true, data: {...}} 형태인 경우 처리
      final responseData = response.data;
      if (responseData is Map && responseData.containsKey('data')) {
        return EquipmentDto.fromJson(responseData['data']);
      } else {
        // 직접 데이터인 경우
        return EquipmentDto.fromJson(responseData);
      }
    } on DioException catch (e) {
      _handleDioException(e);
    }
  }

  @override
  Future<void> deleteEquipment(int id) async {
    try {
      await _apiClient.delete('${ApiEndpoints.equipment}/$id');
    } on DioException catch (e) {
      _handleDioException(e);
    }
  }

  @override
  Future<EquipmentDto> restoreEquipment(int id) async {
    try {
      final response = await _apiClient.put('${ApiEndpoints.equipment}/$id/restore');
      
      // 백엔드 응답 구조에 따라 data 필드에서 추출
      final responseData = response.data;
      return EquipmentDto.fromJson(responseData['data'] ?? responseData);
    } on DioException catch (e) {
      throw ServerException(
        message: e.response?.data['message'] ?? 'Failed to restore equipment',
        statusCode: e.response?.statusCode,
      );
    }
  }

  @override
  Future<EquipmentDto> getEquipmentBySerial(String serial) async {
    try {
      final response = await _apiClient.get('${ApiEndpoints.equipment}/serial/$serial');
      
      // 백엔드 응답 구조에 따라 data 필드에서 추출
      final responseData = response.data;
      return EquipmentDto.fromJson(responseData['data'] ?? responseData);
    } on DioException catch (e) {
      throw ServerException(
        message: e.response?.data['message'] ?? 'Equipment not found by serial',
        statusCode: e.response?.statusCode,
      );
    }
  }

  @override
  Future<EquipmentDto> getEquipmentByBarcode(String barcode) async {
    try {
      final response = await _apiClient.get('${ApiEndpoints.equipment}/barcode/$barcode');
      
      // 백엔드 응답 구조에 따라 data 필드에서 추출
      final responseData = response.data;
      return EquipmentDto.fromJson(responseData['data'] ?? responseData);
    } on DioException catch (e) {
      throw ServerException(
        message: e.response?.data['message'] ?? 'Equipment not found by barcode',
        statusCode: e.response?.statusCode,
      );
    }
  }

  @override
  Future<List<EquipmentDto>> getEquipmentsByCompany(int companyId) async {
    try {
      final response = await _apiClient.get('${ApiEndpoints.equipment}/by-company/$companyId');
      
      print('[Equipment API] Company Filter Response: ${response.data}');
      
      // 백엔드 응답 구조에 따라 data 필드에서 추출
      final responseData = response.data;
      final List<dynamic> equipmentList = responseData['data'] ?? responseData;
      
      return equipmentList.map((json) => EquipmentDto.fromJson(json)).toList();
    } on DioException catch (e) {
      throw ServerException(
        message: e.response?.data['message'] ?? 'Failed to get equipments by company',
        statusCode: e.response?.statusCode,
      );
    }
  }
}