import 'package:dio/dio.dart'; import '../../../../core/logging/logger.dart'; import '../../../../core/network/api_problem.dart'; import '../../../../data/network/api_client.dart'; import '../models/notification_item.dart'; import '../models/notification_list_result.dart'; class NotificationApi { NotificationApi({required ApiClient apiClient}) : _apiClient = apiClient; final ApiClient _apiClient; final Logger _logger = getLogger('features.notifications.data.apis'); Future listNotifications({ int limit = 20, String? cursor, }) async { final queryParts = ['limit=$limit']; if (cursor != null) { queryParts.add('cursor=$cursor'); } final path = '/api/v1/notifications?${queryParts.join("&")}'; try { final json = await _apiClient.getJson(path); final itemsJson = json['items'] as List? ?? []; final items = itemsJson .map((e) => parseNotificationItem(e as Map)) .toList(); return NotificationListResult( items: items, nextCursor: json['nextCursor'] as String?, hasMore: json['hasMore'] as bool? ?? false, ); } on DioException catch (error, stackTrace) { _logger.error( message: 'List notifications failed', error: error, stackTrace: stackTrace, ); throw _mapProblem(error); } } Future getUnreadCount() async { try { final json = await _apiClient.getJson( '/api/v1/notifications/unread-count', ); return json['count'] as int? ?? 0; } on DioException catch (error, stackTrace) { _logger.error( message: 'Get unread count failed', error: error, stackTrace: stackTrace, ); throw _mapProblem(error); } } Future markRead({required String notificationId}) async { _logger.info( message: 'Mark read request started', extra: {'notification_id': notificationId}, ); try { final response = await _apiClient.rawDio.patch>( '/api/v1/notifications/$notificationId/read', ); final item = parseNotificationItem(response.data!); _logger.info( message: 'Mark read request succeeded', extra: {'notification_id': notificationId, 'is_read': item.isRead}, ); return item; } on DioException catch (error, stackTrace) { _logger.error( message: 'Mark read failed', error: error, stackTrace: stackTrace, ); throw _mapProblem(error); } } Future markAllRead() async { _logger.info(message: 'Mark all read request started'); try { final response = await _apiClient.rawDio.patch>( '/api/v1/notifications/mark-all-read', ); final updatedCount = response.data?['updatedCount'] as int? ?? 0; _logger.info( message: 'Mark all read request succeeded', extra: {'updated_count': updatedCount}, ); return updatedCount; } on DioException catch (error, stackTrace) { _logger.error( message: 'Mark all read failed', error: error, stackTrace: stackTrace, ); throw _mapProblem(error); } } ApiProblem _mapProblem(DioException error) { final status = error.response?.statusCode ?? 500; final data = error.response?.data; if (data is Map) { return ApiProblem( status: status, title: (data['title'] as String?) ?? 'Request failed', detail: (data['detail'] as String?) ?? '', code: data['code'] as String?, ); } return ApiProblem( status: status, title: 'Network error', detail: error.message ?? 'Request failed', ); } }