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_history_dto.dart'; import 'package:superport/data/models/equipment/equipment_in_request.dart'; import 'package:superport/data/models/equipment/equipment_io_response.dart'; import 'package:superport/data/models/equipment/equipment_list_dto.dart'; import 'package:superport/data/models/equipment/equipment_out_request.dart'; import 'package:superport/data/models/equipment/equipment_request.dart'; import 'package:superport/data/models/equipment/equipment_response.dart'; abstract class EquipmentRemoteDataSource { Future> getEquipments({ int page = 1, int perPage = 20, String? status, int? companyId, int? warehouseLocationId, String? search, }); Future createEquipment(CreateEquipmentRequest request); Future getEquipmentDetail(int id); Future updateEquipment(int id, UpdateEquipmentRequest request); Future deleteEquipment(int id); Future changeEquipmentStatus(int id, String status, String? reason); Future addEquipmentHistory(int equipmentId, CreateHistoryRequest request); Future> getEquipmentHistory(int equipmentId, {int page = 1, int perPage = 20}); Future equipmentIn(EquipmentInRequest request); Future equipmentOut(EquipmentOutRequest request); } class EquipmentRemoteDataSourceImpl implements EquipmentRemoteDataSource { final ApiClient _apiClient = GetIt.instance(); @override Future> getEquipments({ int page = 1, int perPage = 20, String? status, int? companyId, int? warehouseLocationId, String? search, }) async { try { final queryParams = { 'page': page, 'per_page': perPage, if (status != null) 'status': status, if (companyId != null) 'company_id': companyId, if (warehouseLocationId != null) 'warehouse_location_id': warehouseLocationId, if (search != null && search.isNotEmpty) 'search': search, }; final response = await _apiClient.get( ApiEndpoints.equipment, queryParameters: queryParams, ); if (response.data['success'] == true && response.data['data'] != null) { final List data = response.data['data']; return data.map((json) => EquipmentListDto.fromJson(json)).toList(); } else { throw ServerException( message: response.data['message'] ?? 'Failed to fetch equipment list', ); } } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Network error occurred', statusCode: e.response?.statusCode, ); } } @override Future createEquipment(CreateEquipmentRequest request) async { try { final response = await _apiClient.post( ApiEndpoints.equipment, data: request.toJson(), ); if (response.data['success'] == true && response.data['data'] != null) { return EquipmentResponse.fromJson(response.data['data']); } else { throw ServerException( message: response.data['message'] ?? 'Failed to create equipment', ); } } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Network error occurred', statusCode: e.response?.statusCode, ); } } @override Future getEquipmentDetail(int id) async { try { final response = await _apiClient.get('${ApiEndpoints.equipment}/$id'); if (response.data['success'] == true && response.data['data'] != null) { return EquipmentResponse.fromJson(response.data['data']); } else { throw ServerException( message: response.data['message'] ?? 'Failed to fetch equipment detail', ); } } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Network error occurred', statusCode: e.response?.statusCode, ); } } @override Future updateEquipment(int id, UpdateEquipmentRequest request) async { try { final response = await _apiClient.put( '${ApiEndpoints.equipment}/$id', data: request.toJson(), ); if (response.data['success'] == true && response.data['data'] != null) { return EquipmentResponse.fromJson(response.data['data']); } else { throw ServerException( message: response.data['message'] ?? 'Failed to update equipment', ); } } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Network error occurred', statusCode: e.response?.statusCode, ); } } @override Future deleteEquipment(int id) async { try { final response = await _apiClient.delete('${ApiEndpoints.equipment}/$id'); if (response.data['success'] != true) { throw ServerException( message: response.data['message'] ?? 'Failed to delete equipment', ); } } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Network error occurred', statusCode: e.response?.statusCode, ); } } @override Future changeEquipmentStatus(int id, String status, String? reason) async { try { final response = await _apiClient.patch( '${ApiEndpoints.equipment}/$id/status', data: { 'status': status, if (reason != null) 'reason': reason, }, ); if (response.data['success'] == true && response.data['data'] != null) { return EquipmentResponse.fromJson(response.data['data']); } else { throw ServerException( message: response.data['message'] ?? 'Failed to change equipment status', ); } } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Network error occurred', statusCode: e.response?.statusCode, ); } } @override Future addEquipmentHistory(int equipmentId, CreateHistoryRequest request) async { try { final response = await _apiClient.post( '${ApiEndpoints.equipment}/$equipmentId/history', data: request.toJson(), ); if (response.data['success'] == true && response.data['data'] != null) { return EquipmentHistoryDto.fromJson(response.data['data']); } else { throw ServerException( message: response.data['message'] ?? 'Failed to add equipment history', ); } } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Network error occurred', statusCode: e.response?.statusCode, ); } } @override Future> getEquipmentHistory(int equipmentId, {int page = 1, int perPage = 20}) async { try { final queryParams = { 'page': page, 'per_page': perPage, }; print('[API] Requesting equipment history: ${ApiEndpoints.equipment}/$equipmentId/history'); print('[API] Query params: $queryParams'); final response = await _apiClient.get( '${ApiEndpoints.equipment}/$equipmentId/history', queryParameters: queryParams, ); print('[API] Response status: ${response.statusCode}'); print('[API] Response data type: ${response.data.runtimeType}'); print('[API] Full response: ${response.data}'); // API 응답 구조 확인 if (response.data == null) { print('[API ERROR] Response data is null'); throw ServerException(message: 'Empty response from server'); } // 응답이 Map인지 확인 if (response.data is! Map) { print('[API ERROR] Response is not a Map: ${response.data.runtimeType}'); throw ServerException(message: 'Invalid response format'); } // success 필드 확인 final success = response.data['success']; print('[API] Success field: $success'); if (success == true) { final responseData = response.data['data']; print('[API] Data field type: ${responseData?.runtimeType}'); if (responseData == null) { print('[API] No data field, returning empty list'); return []; } if (responseData is! List) { print('[API ERROR] Data is not a List: ${responseData.runtimeType}'); throw ServerException(message: 'Invalid data format'); } final List data = responseData; print('[API] History data count: ${data.length}'); if (data.isEmpty) { print('[API] Empty history data'); return []; } print('[API] First history item: ${data.first}'); try { final histories = data.map((json) { print('[API] Parsing history item: $json'); return EquipmentHistoryDto.fromJson(json); }).toList(); print('[API] Successfully parsed ${histories.length} history items'); return histories; } catch (e) { print('[API ERROR] Failed to parse history data: $e'); throw ServerException(message: 'Failed to parse history data: $e'); } } else { final errorMessage = response.data['message'] ?? response.data['error'] ?? 'Failed to fetch equipment history'; print('[API ERROR] Request failed: $errorMessage'); throw ServerException(message: errorMessage); } } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Network error occurred', statusCode: e.response?.statusCode, ); } } @override Future equipmentIn(EquipmentInRequest request) async { try { final response = await _apiClient.post( '${ApiEndpoints.equipment}/in', data: request.toJson(), ); if (response.data['success'] == true && response.data['data'] != null) { return EquipmentIoResponse.fromJson(response.data['data']); } else { throw ServerException( message: response.data['message'] ?? 'Failed to process equipment in', ); } } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Network error occurred', statusCode: e.response?.statusCode, ); } } @override Future equipmentOut(EquipmentOutRequest request) async { try { final response = await _apiClient.post( '${ApiEndpoints.equipment}/out', data: request.toJson(), ); if (response.data['success'] == true && response.data['data'] != null) { return EquipmentIoResponse.fromJson(response.data['data']); } else { throw ServerException( message: response.data['message'] ?? 'Failed to process equipment out', ); } } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Network error occurred', statusCode: e.response?.statusCode, ); } } }