/// Datasource distant pour la communication (API) library messaging_remote_datasource; import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:injectable/injectable.dart'; import '../../../../core/config/environment.dart'; import '../../../../core/error/exceptions.dart'; import '../models/message_model.dart'; import '../models/conversation_model.dart'; import '../../domain/entities/message.dart'; @lazySingleton class MessagingRemoteDatasource { final http.Client client; final FlutterSecureStorage secureStorage; MessagingRemoteDatasource({ required this.client, required this.secureStorage, }); /// Headers HTTP avec authentification Future> _getHeaders() async { final token = await secureStorage.read(key: 'access_token'); return { 'Content-Type': 'application/json', 'Accept': 'application/json', if (token != null) 'Authorization': 'Bearer $token', }; } // === CONVERSATIONS === Future> getConversations({ String? organizationId, bool includeArchived = false, }) async { final uri = Uri.parse('${AppConfig.apiBaseUrl}/api/messaging/conversations') .replace(queryParameters: { if (organizationId != null) 'organizationId': organizationId, 'includeArchived': includeArchived.toString(), }); final response = await client.get(uri, headers: await _getHeaders()); if (response.statusCode == 200) { final List jsonList = json.decode(response.body); return jsonList .map((json) => ConversationModel.fromJson(json)) .toList(); } else if (response.statusCode == 401) { throw UnauthorizedException(); } else { throw ServerException('Erreur lors de la récupération des conversations'); } } Future getConversationById(String conversationId) async { final uri = Uri.parse( '${AppConfig.apiBaseUrl}/api/messaging/conversations/$conversationId'); final response = await client.get(uri, headers: await _getHeaders()); if (response.statusCode == 200) { return ConversationModel.fromJson(json.decode(response.body)); } else if (response.statusCode == 404) { throw NotFoundException('Conversation non trouvée'); } else if (response.statusCode == 401) { throw UnauthorizedException(); } else { throw ServerException('Erreur lors de la récupération de la conversation'); } } Future createConversation({ required String name, required List participantIds, String? organizationId, String? description, }) async { final uri = Uri.parse('${AppConfig.apiBaseUrl}/api/messaging/conversations'); final body = json.encode({ 'name': name, 'participantIds': participantIds, if (organizationId != null) 'organizationId': organizationId, if (description != null) 'description': description, }); final response = await client.post( uri, headers: await _getHeaders(), body: body, ); if (response.statusCode == 201 || response.statusCode == 200) { return ConversationModel.fromJson(json.decode(response.body)); } else if (response.statusCode == 401) { throw UnauthorizedException(); } else { throw ServerException('Erreur lors de la création de la conversation'); } } // === MESSAGES === Future> getMessages({ required String conversationId, int? limit, String? beforeMessageId, }) async { final uri = Uri.parse( '${AppConfig.apiBaseUrl}/api/messaging/conversations/$conversationId/messages') .replace(queryParameters: { if (limit != null) 'limit': limit.toString(), if (beforeMessageId != null) 'beforeMessageId': beforeMessageId, }); final response = await client.get(uri, headers: await _getHeaders()); if (response.statusCode == 200) { final List jsonList = json.decode(response.body); return jsonList.map((json) => MessageModel.fromJson(json)).toList(); } else if (response.statusCode == 401) { throw UnauthorizedException(); } else { throw ServerException('Erreur lors de la récupération des messages'); } } Future sendMessage({ required String conversationId, required String content, List? attachments, MessagePriority priority = MessagePriority.normal, }) async { final uri = Uri.parse( '${AppConfig.apiBaseUrl}/api/messaging/conversations/$conversationId/messages'); final body = json.encode({ 'content': content, if (attachments != null) 'attachments': attachments, 'priority': priority.name, }); final response = await client.post( uri, headers: await _getHeaders(), body: body, ); if (response.statusCode == 201 || response.statusCode == 200) { return MessageModel.fromJson(json.decode(response.body)); } else if (response.statusCode == 401) { throw UnauthorizedException(); } else { throw ServerException('Erreur lors de l\'envoi du message'); } } Future sendBroadcast({ required String organizationId, required String subject, required String content, MessagePriority priority = MessagePriority.normal, List? attachments, }) async { final uri = Uri.parse('${AppConfig.apiBaseUrl}/api/messaging/broadcast'); final body = json.encode({ 'organizationId': organizationId, 'subject': subject, 'content': content, 'priority': priority.name, if (attachments != null) 'attachments': attachments, }); final response = await client.post( uri, headers: await _getHeaders(), body: body, ); if (response.statusCode == 201 || response.statusCode == 200) { return MessageModel.fromJson(json.decode(response.body)); } else if (response.statusCode == 401) { throw UnauthorizedException(); } else if (response.statusCode == 403) { throw ForbiddenException('Permission insuffisante pour envoyer un broadcast'); } else { throw ServerException('Erreur lors de l\'envoi du broadcast'); } } Future markMessageAsRead(String messageId) async { final uri = Uri.parse('${AppConfig.apiBaseUrl}/api/messaging/messages/$messageId/read'); final response = await client.put(uri, headers: await _getHeaders()); if (response.statusCode != 200 && response.statusCode != 204) { if (response.statusCode == 401) { throw UnauthorizedException(); } else { throw ServerException('Erreur lors du marquage du message comme lu'); } } } Future getUnreadCount({String? organizationId}) async { final uri = Uri.parse('${AppConfig.apiBaseUrl}/api/messaging/unread/count') .replace(queryParameters: { if (organizationId != null) 'organizationId': organizationId, }); final response = await client.get(uri, headers: await _getHeaders()); if (response.statusCode == 200) { final data = json.decode(response.body); return data['count'] as int; } else if (response.statusCode == 401) { throw UnauthorizedException(); } else { throw ServerException('Erreur lors de la récupération du compte non lu'); } } }