import 'package:dio/dio.dart'; import 'package:injectable/injectable.dart'; import '../../../../core/network/api_client.dart'; import '../../../../core/utils/logger.dart'; import '../models/dashboard_stats_model.dart'; import '../models/membre_dashboard_synthese_model.dart'; import '../models/compte_adherent_model.dart'; import '../../../../core/error/exceptions.dart'; abstract class DashboardRemoteDataSource { Future getDashboardData(String organizationId, String userId); /// Dashboard personnel du membre connecté (sans organisationId). GET /api/dashboard/membre/me Future getMemberDashboardData(); /// Synthèse des cotisations du membre connecté. GET /api/cotisations/mes-cotisations/synthese /// Utilisé en fallback quand les montants de getMemberDashboardData() sont à 0. Future?> getMesCotisationsSynthese(); /// Compte adhérent unifié (soldes, crédits, capacité d'emprunt). GET /api/membres/mon-compte Future getCompteAdherent(); Future getDashboardStats(String organizationId, String userId); Future> getRecentActivities(String organizationId, String userId, {int limit = 10}); Future> getUpcomingEvents(String organizationId, String userId, {int limit = 5}); } @Injectable(as: DashboardRemoteDataSource) class DashboardRemoteDataSourceImpl implements DashboardRemoteDataSource { final ApiClient apiClient; DashboardRemoteDataSourceImpl(this.apiClient); @override Future getDashboardData(String organizationId, String userId) async { try { final response = await apiClient.get( '/api/v1/dashboard/data', queryParameters: { 'organizationId': organizationId, 'userId': userId, }, ); if (response.statusCode == 200) { return DashboardDataModel.fromJson(response.data); } else { throw ServerException('Failed to load dashboard data: ${response.statusCode}'); } } on DioException catch (e) { AppLogger.error('DashboardRemoteDataSource: getDashboardData', error: e); throw ServerException('Network error: ${e.message}'); } catch (e, st) { AppLogger.error('DashboardRemoteDataSource: getDashboardData', error: e, stackTrace: st); rethrow; } } @override Future getMemberDashboardData() async { try { final response = await apiClient.get('/api/dashboard/membre/me'); if (response.statusCode == 200) { return MembreDashboardSyntheseModel.fromJson( response.data is Map ? response.data as Map : Map.from(response.data as Map), ); } else { throw ServerException('Failed to load member dashboard: ${response.statusCode}'); } } on DioException catch (e) { if (e.response?.statusCode == 404) { throw const NotFoundException('Profil membre non trouvé'); } AppLogger.error('DashboardRemoteDataSource: getMemberDashboardData', error: e); throw ServerException('Network error: ${e.message}'); } catch (e, st) { AppLogger.error('DashboardRemoteDataSource: getMemberDashboardData', error: e, stackTrace: st); rethrow; } } @override Future?> getMesCotisationsSynthese() async { try { final response = await apiClient.get('/api/cotisations/mes-cotisations/synthese'); if (response.statusCode == 200 && response.data != null) { return response.data is Map ? response.data as Map : Map.from(response.data as Map); } return null; } catch (e, st) { AppLogger.error('DashboardRemoteDataSource: getMesCotisationsSynthese échoué', error: e, stackTrace: st); rethrow; } } @override Future getCompteAdherent() async { try { final response = await apiClient.get('/api/membres/mon-compte'); if (response.statusCode == 200) { return CompteAdherentModel.fromJson( response.data is Map ? response.data as Map : Map.from(response.data as Map), ); } else { throw ServerException('Failed to load adherent account: ${response.statusCode}'); } } on DioException catch (e) { if (e.response?.statusCode == 404) { throw const NotFoundException('Compte adhérent non trouvé'); } AppLogger.error('DashboardRemoteDataSource: getCompteAdherent', error: e); throw ServerException('Network error: ${e.message}'); } catch (e, st) { AppLogger.error('DashboardRemoteDataSource: getCompteAdherent', error: e, stackTrace: st); rethrow; } } @override Future getDashboardStats(String organizationId, String userId) async { try { final response = await apiClient.get( '/api/v1/dashboard/stats', queryParameters: { 'organizationId': organizationId, 'userId': userId, }, ); if (response.statusCode == 200) { return DashboardStatsModel.fromJson(response.data); } else { throw ServerException('Failed to load dashboard stats: ${response.statusCode}'); } } on DioException catch (e) { AppLogger.error('DashboardRemoteDataSource: getDashboardStats', error: e); throw ServerException('Network error: ${e.message}'); } catch (e, st) { AppLogger.error('DashboardRemoteDataSource: getDashboardStats', error: e, stackTrace: st); rethrow; } } @override Future> getRecentActivities( String organizationId, String userId, { int limit = 10, }) async { try { final response = await apiClient.get( '/api/v1/dashboard/activities', queryParameters: { 'organizationId': organizationId, 'userId': userId, 'limit': limit, }, ); if (response.statusCode == 200) { final List data = response.data['activities'] ?? []; return data.map((json) => RecentActivityModel.fromJson(json)).toList(); } else { throw ServerException('Failed to load recent activities: ${response.statusCode}'); } } on DioException catch (e) { AppLogger.error('DashboardRemoteDataSource: getRecentActivities', error: e); throw ServerException('Network error: ${e.message}'); } catch (e, st) { AppLogger.error('DashboardRemoteDataSource: getRecentActivities', error: e, stackTrace: st); rethrow; } } @override Future> getUpcomingEvents( String organizationId, String userId, { int limit = 5, }) async { try { final response = await apiClient.get( '/api/v1/dashboard/events/upcoming', queryParameters: { 'organizationId': organizationId, 'userId': userId, 'limit': limit, }, ); if (response.statusCode == 200) { final List data = response.data['events'] ?? []; return data.map((json) => UpcomingEventModel.fromJson(json)).toList(); } else { throw ServerException('Failed to load upcoming events: ${response.statusCode}'); } } on DioException catch (e) { AppLogger.error('DashboardRemoteDataSource: getUpcomingEvents', error: e); throw ServerException('Network error: ${e.message}'); } catch (e, st) { AppLogger.error('DashboardRemoteDataSource: getUpcomingEvents', error: e, stackTrace: st); rethrow; } } }