using Microsoft.EntityFrameworkCore; using vendorApproverBackend.Entities; using vendorApproverBackend.Requests; using vendorApproverBackend.Responses; using vendorApproverBackend.Interfaces; using vendorApproverBackend.Data; using vendorApproverBackend.Enums; namespace vendorApproverBackend.Services; public class NotificationService { private readonly ILogger _logger; private readonly DataContext _context; private readonly UserService _userService; // Direct class usage as requested private readonly INotificationService _notificationService; public NotificationService( ILogger logger, DataContext context, UserService userService, INotificationService notificationService) { _logger = logger; _context = context; _userService = userService; _notificationService = notificationService; } public async Task SaveAsync(NotificationModel model) { try { if (model.Id == 0) { await _context.NotificationModels.AddAsync(model); } else { _context.NotificationModels.Update(model); } await _context.SaveChangesAsync(); return model; } catch (Exception ex) { _logger.LogError(ex, "Error saving notification model."); throw new Exception("Error saving data.", ex); } } public async Task ExistsByIdAsync(long id) { return await _context.NotificationModels.AnyAsync(n => n.Id == id); } public async Task FindByIdAsync(long id) { var notification = await _context.NotificationModels .FirstOrDefaultAsync(n => n.Id == id); if (notification == null) { //throw new NotFoundException($"Notification with id {id} not found."); } return notification; } // Corresponds to allnotificationbyuser and all_my_notification_waiting public async Task> AllNotificationByUserAsync(int page, int size, User user) { if (size <= 0) size = 3; var query = _context.NotificationModels .Where(n => n.ReciverId == user.Id) .OrderByDescending(n => n.Timestmp); var totalCount = await query.CountAsync(); var resultlist = await query .Skip(page * size) .Take(size) .ToListAsync(); // Uses the PagedResult DTO you provided return new PagedResult(resultlist, totalCount, page, size); } // Corresponds to allUnreadNotificationByUser public async Task AllUnreadNotificationByUserAsync(User user) { var unreadStatus = new List { states.WAITING, states.DELIVERED, states.SENDING }; return await _context.NotificationModels .CountAsync(n => n.ReciverId == user.Id && unreadStatus.Contains(n.Status)); } // Corresponds to getUnreadNotificationByUser public async Task> GetUnreadNotificationByUserAsync(User user) { var unreadStatus = new List { states.WAITING, states.DELIVERED, states.SENDING }; return await _context.NotificationModels .Where(n => n.ReciverId == user.Id && unreadStatus.Contains(n.Status)) .ToListAsync(); } // Corresponds to read_my_waiting_notification logic public async Task> ReadMyWaitingNotificationAsync(List notificationIds, User user) { var updatedNotifications = new List(); List notificationsToUpdate; if (notificationIds != null && notificationIds.Any()) { // Process specific IDs notificationsToUpdate = await _context.NotificationModels .Where(n => notificationIds.Contains(n.Id) && n.ReciverId == user.Id) .ToListAsync(); // Check for invalid or unauthorized IDs (where count doesn't match requested valid IDs) if (notificationsToUpdate.Count != notificationIds.Count(id => ExistsByIdAsync(id).Result)) { // This attempts to replicate the Spring's early exit for 'invalid id' var invalidId = notificationIds.Except(notificationsToUpdate.Select(n => n.Id)).FirstOrDefault(); // if (invalidId != 0) throw new BadRequestException($"invalid id {invalidId}"); } } else { // Process all unread notifications for the user notificationsToUpdate = await GetUnreadNotificationByUserAsync(user); } foreach (var notif in notificationsToUpdate.Where(n => n.Status != states.READ)) { notif.Status = states.READ; updatedNotifications.Add(notif); } if (updatedNotifications.Any()) { await _context.SaveChangesAsync(); } return notificationsToUpdate; // Return all processed notifications (read or already read) } // Corresponds to read_notification logic public async Task ReadNotificationAsync(long notifId, User user) { var notif = await FindByIdAsync(notifId); // Finds by ID, throws if not found if (notif.ReciverId != user.Id) { throw new UnauthorizedAccessException("User is not the receiver of this notification."); } notif.Status = states.READ; await SaveAsync(notif); return notif; } public async Task SendDynamicNotificationsAsync(DynamicNotificationRequest request, long currentUserId) { try { var notification = new NotificationModel { SenderId = currentUserId, Subject = request.Subject, Content = request.Content, Action = request.Action, ActionId = request.ActionId, LogUrl = request.LogUrl, Status = states.WAITING // defaults to WAITING }; var usersIds = new List(); // Get users by roles if (request.Roles != null && request.Roles.Count > 0) { foreach (var role in request.Roles) { var roleUserIds = await _userService.GetUserIdsBasedonRoleAsync(role); usersIds.AddRange(roleUserIds); } } // Get users by explicit Ids if (request.Ids != null && request.Ids.Count > 0) { foreach (var id in request.Ids) { if (await _userService.ExistByIdAsync(id)) { usersIds.Add(id); } } } // Remove duplicates (optional but recommended) usersIds = usersIds.Distinct().ToList(); // Send notifications if (usersIds.Count > 0) { await _notificationService.SendNotificationToListOfUsers(usersIds, notification); } } catch (Exception ex) { _logger.LogError(ex, "Failed to send notification for ActionId {ActionId}", request.ActionId); } } }