import 'package:dio/dio.dart'; import '../../../../core/models/membre_search_criteria.dart'; import '../../../../core/models/membre_search_result.dart'; /// Service pour la recherche avancée de membres /// Gère les appels API vers l'endpoint de recherche sophistiquée class MembreSearchService { final Dio _dio; MembreSearchService(this._dio); /// Effectue une recherche avancée de membres /// /// [criteria] Critères de recherche /// [page] Numéro de page (0-based) /// [size] Taille de la page /// [sortField] Champ de tri /// [sortDirection] Direction du tri (asc/desc) /// /// Returns [MembreSearchResult] avec les résultats paginés Future searchMembresAdvanced({ required MembreSearchCriteria criteria, int page = 0, int size = 20, String sortField = 'nom', String sortDirection = 'asc', }) async { print('Recherche avancée de membres: ${criteria.description}'); try { // Validation des critères if (!criteria.hasAnyCriteria) { throw Exception('Au moins un critère de recherche doit être spécifié'); } if (!criteria.isValid) { throw Exception('Critères de recherche invalides'); } // Préparation des paramètres de requête final queryParams = { 'page': page.toString(), 'size': size.toString(), 'sort': sortField, 'direction': sortDirection, }; // Appel API final response = await _dio.post( '/api/membres/search/advanced', data: criteria.toJson(), queryParameters: queryParams, ); // Parsing de la réponse final result = MembreSearchResult.fromJson(response.data); print('Recherche terminée: ${result.totalElements} résultats en ${result.executionTimeMs}ms'); return result; } on DioException catch (e) { print('Erreur lors de la recherche avancée: $e'); rethrow; } catch (e) { print('Erreur inattendue lors de la recherche: $e'); rethrow; } } /// Recherche rapide par terme général /// /// [query] Terme de recherche /// [page] Numéro de page /// [size] Taille de la page /// /// Returns [MembreSearchResult] avec les résultats Future quickSearch({ required String query, int page = 0, int size = 20, }) async { final criteria = MembreSearchCriteria.quickSearch(query); return searchMembresAdvanced( criteria: criteria, page: page, size: size, ); } /// Recherche des membres actifs uniquement /// /// [page] Numéro de page /// [size] Taille de la page /// /// Returns [MembreSearchResult] avec les membres actifs Future searchActiveMembers({ int page = 0, int size = 20, }) async { return searchMembresAdvanced( criteria: MembreSearchCriteria.activeMembers, page: page, size: size, ); } /// Recherche des membres du bureau /// /// [page] Numéro de page /// [size] Taille de la page /// /// Returns [MembreSearchResult] avec les membres du bureau Future searchBureauMembers({ int page = 0, int size = 20, }) async { return searchMembresAdvanced( criteria: MembreSearchCriteria.bureauMembers, page: page, size: size, ); } /// Recherche par organisation /// /// [organisationIds] Liste des IDs d'organisations /// [page] Numéro de page /// [size] Taille de la page /// /// Returns [MembreSearchResult] avec les membres des organisations Future searchByOrganisations({ required List organisationIds, int page = 0, int size = 20, }) async { final criteria = MembreSearchCriteria( organisationIds: organisationIds, statut: 'ACTIF', ); return searchMembresAdvanced( criteria: criteria, page: page, size: size, ); } /// Recherche par tranche d'âge /// /// [ageMin] Âge minimum /// [ageMax] Âge maximum /// [page] Numéro de page /// [size] Taille de la page /// /// Returns [MembreSearchResult] avec les membres dans la tranche d'âge Future searchByAgeRange({ int? ageMin, int? ageMax, int page = 0, int size = 20, }) async { final criteria = MembreSearchCriteria( ageMin: ageMin, ageMax: ageMax, statut: 'ACTIF', ); return searchMembresAdvanced( criteria: criteria, page: page, size: size, ); } /// Recherche par région /// /// [region] Nom de la région /// [page] Numéro de page /// [size] Taille de la page /// /// Returns [MembreSearchResult] avec les membres de la région Future searchByRegion({ required String region, int page = 0, int size = 20, }) async { final criteria = MembreSearchCriteria( region: region, statut: 'ACTIF', ); return searchMembresAdvanced( criteria: criteria, page: page, size: size, ); } /// Recherche par rôles /// /// [roles] Liste des rôles /// [page] Numéro de page /// [size] Taille de la page /// /// Returns [MembreSearchResult] avec les membres ayant ces rôles Future searchByRoles({ required List roles, int page = 0, int size = 20, }) async { final criteria = MembreSearchCriteria( roles: roles, statut: 'ACTIF', ); return searchMembresAdvanced( criteria: criteria, page: page, size: size, ); } /// Recherche par période d'adhésion /// /// [dateMin] Date minimum (ISO 8601) /// [dateMax] Date maximum (ISO 8601) /// [page] Numéro de page /// [size] Taille de la page /// /// Returns [MembreSearchResult] avec les membres adhérés dans la période Future searchByAdhesionPeriod({ String? dateMin, String? dateMax, int page = 0, int size = 20, }) async { final criteria = MembreSearchCriteria( dateAdhesionMin: dateMin, dateAdhesionMax: dateMax, statut: 'ACTIF', ); return searchMembresAdvanced( criteria: criteria, page: page, size: size, ); } /// Valide les critères de recherche avant envoi bool validateCriteria(MembreSearchCriteria criteria) { if (!criteria.hasAnyCriteria) { print('Aucun critère de recherche spécifié'); return false; } if (!criteria.isValid) { print('Critères de recherche invalides: ${criteria.description}'); return false; } return true; } /// Estime le temps de recherche basé sur les critères Duration estimateSearchTime(MembreSearchCriteria criteria) { // Estimation basique - peut être améliorée avec des métriques réelles int complexityScore = 0; if (criteria.query?.isNotEmpty == true) complexityScore += 2; if (criteria.organisationIds?.isNotEmpty == true) complexityScore += 1; if (criteria.roles?.isNotEmpty == true) complexityScore += 1; if (criteria.ageMin != null || criteria.ageMax != null) complexityScore += 1; if (criteria.dateAdhesionMin != null || criteria.dateAdhesionMax != null) complexityScore += 1; // Temps de base + complexité const baseTime = 100; // 100ms de base final additionalTime = complexityScore * 50; // 50ms par critère return Duration(milliseconds: baseTime + additionalTime); } }