using FluentResults; using MediatR; using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; using NexusReader.Application.Commands.Sync; using NexusReader.Domain.Entities; using NexusReader.Data.Persistence; using NexusReader.Infrastructure.RealTime; namespace NexusReader.Infrastructure.Handlers; public class UpdateReadingProgressCommandHandler : IRequestHandler { private readonly IDbContextFactory _dbContextFactory; private readonly IHubContext _hubContext; public UpdateReadingProgressCommandHandler( IDbContextFactory dbContextFactory, IHubContext hubContext) { _dbContextFactory = dbContextFactory; _hubContext = hubContext; } public async Task Handle(UpdateReadingProgressCommand request, CancellationToken cancellationToken) { using var context = await _dbContextFactory.CreateDbContextAsync(cancellationToken); var user = await context.Users.FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken); if (user == null) { return Result.Fail("User not found."); } var now = DateTime.UtcNow; user.LastReadPageId = request.PageId; user.LastReadAt = now; await context.SaveChangesAsync(cancellationToken); // Broadcast to other devices var group = _hubContext.Clients.Group($"User_{request.UserId}"); if (!string.IsNullOrEmpty(request.ExcludedConnectionId)) { await _hubContext.Clients .GroupExcept($"User_{request.UserId}", request.ExcludedConnectionId) .SendAsync("ProgressUpdated", request.PageId, now, cancellationToken); } else { await group.SendAsync("ProgressUpdated", request.PageId, now, cancellationToken); } return Result.Ok(); } }