import 'package:em2rp/services/api_service.dart'; import 'package:em2rp/utils/debug_log.dart'; /// Repository pour gérer toutes les opérations sur les équipements. class EquipmentRepository { final ApiService _apiService; EquipmentRepository(this._apiService); /// Récupère tous les équipements (avec masquage des prix selon permissions) Future>> getEquipments() async { try { print('[EquipmentRepository] Calling getEquipments API...'); final result = await _apiService.call('getEquipments', {}); print('[EquipmentRepository] API call successful, parsing result...'); final equipments = result['equipments'] as List?; if (equipments == null) { print('[EquipmentRepository] No equipments in result'); return []; } print('[EquipmentRepository] Found ${equipments.length} equipments'); return equipments.map((e) => e as Map).toList(); } catch (e) { print('[EquipmentRepository] Error getting equipments: $e'); throw Exception('Erreur lors de la récupération des équipements: $e'); } } /// Récupère plusieurs équipements par leurs IDs Future>> getEquipmentsByIds( List equipmentIds) async { try { if (equipmentIds.isEmpty) return []; print( '[EquipmentRepository] Getting equipments by IDs: ${equipmentIds.length} items'); final result = await _apiService.call('getEquipmentsByIds', { 'equipmentIds': equipmentIds, }); final equipments = result['equipments'] as List?; if (equipments == null) { print('[EquipmentRepository] No equipments in result'); return []; } print('[EquipmentRepository] Found ${equipments.length} equipments by IDs'); return equipments.map((e) => e as Map).toList(); } catch (e) { print('[EquipmentRepository] Error getting equipments by IDs: $e'); throw Exception('Erreur lors de la récupération des équipements: $e'); } } /// Récupère les équipements avec pagination et filtrage Future> getEquipmentsPaginated({ int limit = 20, String? startAfter, String? category, String? status, String? searchQuery, String sortBy = 'id', String sortOrder = 'asc', }) async { try { final params = { 'limit': limit, 'sortBy': sortBy, 'sortOrder': sortOrder, }; if (startAfter != null) params['startAfter'] = startAfter; if (category != null) params['category'] = category; if (status != null) params['status'] = status; if (searchQuery != null && searchQuery.isNotEmpty) { params['searchQuery'] = searchQuery; } final result = await (_apiService as FirebaseFunctionsApiService).callPaginated( 'getEquipmentsPaginated', params, ); return { 'equipments': (result['equipments'] as List?) ?.map((e) => e as Map) .toList() ?? [], 'hasMore': result['hasMore'] as bool? ?? false, 'lastVisible': result['lastVisible'] as String?, 'total': result['total'] as int? ?? 0, }; } catch (e) { DebugLog.error('[EquipmentRepository] Error in getEquipmentsPaginated', e); throw Exception( 'Erreur lors de la récupération paginée des équipements: $e'); } } /// Crée un équipement Future createEquipment( String equipmentId, Map data) async { try { final equipmentData = Map.from(data); equipmentData['id'] = equipmentId; await _apiService.call('createEquipment', equipmentData); } catch (e) { throw Exception('Erreur lors de la création de l\'équipement: $e'); } } /// Met à jour un équipement Future updateEquipment( String equipmentId, Map data) async { try { await _apiService.call('updateEquipment', { 'equipmentId': equipmentId, 'data': data, }); } catch (e) { throw Exception('Erreur lors de la mise à jour de l\'équipement: $e'); } } /// Supprime un équipement Future deleteEquipment(String equipmentId, {bool forceDelete = false}) async { try { await _apiService.call('deleteEquipment', { 'equipmentId': equipmentId, 'forceDelete': forceDelete, }); } on ApiException { rethrow; } catch (e) { throw Exception('Erreur lors de la suppression de l\'équipement: $e'); } } /// Met à jour uniquement le statut d'un équipement Future updateEquipmentStatusOnly({ required String equipmentId, String? status, int? availableQuantity, }) async { try { final data = {'equipmentId': equipmentId}; if (status != null) data['status'] = status; if (availableQuantity != null) { data['availableQuantity'] = availableQuantity; } await _apiService.call('updateEquipmentStatusOnly', data); } catch (e) { throw Exception( 'Erreur lors de la mise à jour du statut de l\'équipement: $e'); } } /// Recherche rapide (autocomplétion) Future>> quickSearch( String query, { int limit = 10, bool includeEquipments = true, bool includeContainers = true, }) async { try { return await (_apiService as FirebaseFunctionsApiService).quickSearch( query, limit: limit, includeEquipments: includeEquipments, includeContainers: includeContainers, ); } catch (e) { DebugLog.error('[EquipmentRepository] Error in quickSearch', e); return []; } } /// Recherche des équipements pour l'assistant IA avec fallback paginé. Future>> searchEquipmentsForAssistant({ required String query, int limit = 12, }) async { final normalizedQuery = query.trim(); if (normalizedQuery.isEmpty) { return []; } try { final quickResults = await quickSearch( normalizedQuery, limit: limit, includeEquipments: true, includeContainers: false, ); final equipmentResults = quickResults .where((item) => (item['type']?.toString().toLowerCase() ?? '') == 'equipment') .map(_normalizeAssistantEquipment) .toList(); if (equipmentResults.isNotEmpty) { return equipmentResults; } final paginated = await getEquipmentsPaginated( limit: limit, searchQuery: normalizedQuery, sortBy: 'id', sortOrder: 'asc', ); final equipments = paginated['equipments'] as List>? ?? []; return equipments.map(_normalizeAssistantEquipment).toList(); } catch (e) { DebugLog.error('[EquipmentRepository] Error in searchEquipmentsForAssistant', e); throw Exception('Erreur lors de la recherche de matériel: $e'); } } /// Vérifie la disponibilité d'un équipement dans un format normalisé pour l'IA. Future> checkEquipmentAvailabilityForAssistant({ required String equipmentId, required DateTime startDate, required DateTime endDate, String? excludeEventId, }) async { try { final result = await checkEquipmentAvailability( equipmentId: equipmentId, startDate: startDate, endDate: endDate, excludeEventId: excludeEventId, ); final available = result['available'] as bool? ?? true; final conflicts = (result['conflicts'] as List? ?? const []) .whereType>() .map((conflict) { final eventData = conflict['eventData'] as Map? ?? const {}; final eventName = (eventData['Name'] ?? conflict['eventName'] ?? '').toString(); return { 'eventId': conflict['eventId']?.toString() ?? '', 'eventName': eventName, 'overlapDays': conflict['overlapDays'] as int? ?? 0, }; }).toList(); return { 'equipmentId': equipmentId, 'available': available, 'conflictCount': conflicts.length, 'conflicts': conflicts, }; } catch (e) { DebugLog.error( '[EquipmentRepository] Error in checkEquipmentAvailabilityForAssistant', e); throw Exception('Erreur lors de la vérification de disponibilité: $e'); } } /// Vérifie la disponibilité d'un équipement Future> checkEquipmentAvailability({ required String equipmentId, required DateTime startDate, required DateTime endDate, String? excludeEventId, }) async { try { final result = await _apiService.call('checkEquipmentAvailability', { 'equipmentId': equipmentId, 'startDate': startDate.toIso8601String(), 'endDate': endDate.toIso8601String(), if (excludeEventId != null) 'excludeEventId': excludeEventId, }); return result; } catch (e) { throw Exception('Erreur lors de la vérification de disponibilité: $e'); } } /// Récupère tous les IDs d'équipements et conteneurs en conflit pour une période /// Optimisé : une seule requête au lieu d'une par équipement Future> getConflictingEquipmentIds({ required DateTime startDate, required DateTime endDate, String? excludeEventId, int installationTime = 0, int disassemblyTime = 0, }) async { try { final result = await _apiService.call('getConflictingEquipmentIds', { 'startDate': startDate.toIso8601String(), 'endDate': endDate.toIso8601String(), if (excludeEventId != null) 'excludeEventId': excludeEventId, 'installationTime': installationTime, 'disassemblyTime': disassemblyTime, }); return result; } catch (e) { throw Exception( 'Erreur lors de la récupération des équipements en conflit: $e'); } } Map _normalizeAssistantEquipment(Map item) { return { 'id': (item['id'] ?? '').toString(), 'name': (item['name'] ?? item['id'] ?? '').toString(), 'category': (item['category'] ?? '').toString(), 'status': (item['status'] ?? '').toString(), 'brand': item['brand']?.toString(), 'model': item['model']?.toString(), 'availableQuantity': item['availableQuantity'], 'totalQuantity': item['totalQuantity'], }; } /// Récupère toutes les maintenances Future>> getMaintenances( {String? equipmentId}) async { try { final data = {}; if (equipmentId != null) data['equipmentId'] = equipmentId; final result = await _apiService.call('getMaintenances', data); final maintenances = result['maintenances'] as List?; if (maintenances == null) return []; return maintenances.map((e) => e as Map).toList(); } catch (e) { throw Exception('Erreur lors de la récupération des maintenances: $e'); } } /// Supprime une maintenance Future deleteMaintenance(String maintenanceId) async { try { await _apiService .call('deleteMaintenance', {'maintenanceId': maintenanceId}); } catch (e) { throw Exception('Erreur lors de la suppression de la maintenance: $e'); } } }