using Application.Abstractions.Data; using Application.Abstractions.Hub; using Application.Abstractions.Notification; using Domain.Entities.Notifications.ValueObject; using Infrastructure.Hubs; using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; namespace Infrastructure.Notification; internal sealed class NotificationService( IAppDbContext db, IHubContext? appHub = null ) : INotificationService { public async Task SendAsync( int memberID, NotificationType type, string title, string message, string? actionUrl, string? relatedType, int? relatedID, string? imageUrl, CancellationToken ct) { var notification = Domain.Entities.Notifications.Notification.Create( memberID, type, title, message, actionUrl, relatedType, relatedID, imageUrl ); db.Notification.Add(notification); await db.SaveChangesAsync(ct); // SignalR Push (Hub가 등록된 경우에만) if (appHub is not null) { await appHub.Clients.Group($"member:{memberID}").ReceiveNotification(new { notification.ID, notification.Type, notification.Title, notification.Message, notification.ActionUrl, notification.ImageUrl, notification.CreatedAt }); var unreadNotif = await db.Notification.CountAsync(n => n.MemberID == memberID && !n.IsRead, ct); var unreadNote = await db.Note.CountAsync(n => n.ReceiverMemberID == memberID && !n.IsDeletedByReceiver && !n.IsRead, ct); await appHub.Clients.Group($"member:{memberID}").ReceiveUnreadCounts(unreadNotif, unreadNote); } } public async Task SendToManyAsync( IEnumerable memberIDs, NotificationType type, string title, string message, string? actionUrl, string? relatedType, int? relatedID, string? imageUrl, CancellationToken ct) { foreach (var memberID in memberIDs) { await SendAsync(memberID, type, title, message, actionUrl, relatedType, relatedID, imageUrl, ct); } } }