using Microsoft.EntityFrameworkCore; /// /// Provides filtered, sorted work queue views for each workflow stage. /// All queues sort by UpdatedAt ASC to enforce FIFO processing — the oldest /// pending item is always at the top of the queue. /// public class WorkQueueService : IWorkQueueService { private readonly AppDbContext _db; public WorkQueueService(AppDbContext db) { _db = db; } public async Task GetVerificationQueueAsync(int page, int pageSize) { var query = _db.DigitizationBatches .Where(b => b.Status == BatchStatus.PendingVerification) .OrderBy(b => b.UpdatedAt); return await BuildQueueResponseAsync("verification", query, page, pageSize); } public async Task GetEntryQueueAsync(int page, int pageSize) { var entryStatuses = new[] { BatchStatus.Uploaded, BatchStatus.InEntry, BatchStatus.Rejected }; var query = _db.DigitizationBatches .Where(b => entryStatuses.Contains(b.Status)) .OrderBy(b => b.UpdatedAt); return await BuildQueueResponseAsync("entry", query, page, pageSize); } public async Task GetClinicalApprovalQueueAsync(int page, int pageSize) { var query = _db.DigitizationBatches .Where(b => b.Status == BatchStatus.AwaitingClinicalApproval) .OrderBy(b => b.UpdatedAt); return await BuildQueueResponseAsync("clinical-approval", query, page, pageSize); } private async Task BuildQueueResponseAsync( string queueName, IOrderedQueryable query, int page, int pageSize) { var totalCount = await query.CountAsync(); var totalPages = (int)Math.Ceiling((double)totalCount / pageSize); var items = await query .Include(b => b.EnteredByUser) .Include(b => b.Events) .Skip((page - 1) * pageSize) .Take(pageSize) .Select(b => new WorkQueueItemResponse( b.Id, b.Status.ToDbString(), b.BatchType.ToDbString(), b.Track.ToDbString(), b.PatientId, b.EnteredByUserId, b.EnteredByUser != null ? b.EnteredByUser.FullName : null, b.RejectionReason, b.CreatedAt, b.UpdatedAt, b.Events.Count )) .ToListAsync(); return new WorkQueueResponse(queueName, items, page, pageSize, totalCount, totalPages); } }