using Data.SeaHavenIndustries; using Microsoft.EntityFrameworkCore; using SeaHaven.DataServices.Helpers; using SeaHaven.DataServices.Interfaces; namespace SeaHaven.DataServices.Implementation { public class WorkOrderMediaDataService : IWorkOrderMediaDataService { private readonly ApplicationDbContext _context; public WorkOrderMediaDataService(ApplicationDbContext context) { _context = context; } public Task GetWorkOrderForMediaAuthAsync( int workOrderId, int? accountId, CancellationToken cancellationToken) { var query = WorkOrderBoardQueryFilters.ApplyBaseScope(_context.workOrders.AsNoTracking()); if (accountId.HasValue) query = WorkOrderBoardQueryFilters.ApplyAccountScope(query, accountId.Value); return query.FirstOrDefaultAsync(w => w.Id == workOrderId, cancellationToken); } public Task GetTrackedWorkOrderAsync( int workOrderId, int? accountId, CancellationToken cancellationToken) { var query = WorkOrderBoardQueryFilters.ApplyBaseScope(_context.workOrders); if (accountId.HasValue) query = WorkOrderBoardQueryFilters.ApplyAccountScope(query, accountId.Value); return query.FirstOrDefaultAsync(w => w.Id == workOrderId, cancellationToken); } public Task GetAttachmentForReadAsync( int mediaId, int workOrderId, CancellationToken cancellationToken) => _context.workOrderAttachments .AsNoTracking() .FirstOrDefaultAsync( a => a.Id == mediaId && a.WorkorderId == workOrderId && a.IsDeleted != true, cancellationToken); public Task GetTrackedAttachmentAsync(int mediaId, int workOrderId, CancellationToken cancellationToken) => _context.workOrderAttachments.FirstOrDefaultAsync( a => a.Id == mediaId && a.WorkorderId == workOrderId && a.IsDeleted != true, cancellationToken); public void TrackAttachment(WorkOrderAttachments attachment) => _context.workOrderAttachments.Add(attachment); public async Task> ListActiveAttachmentUrlsAsync( int workOrderId, CancellationToken cancellationToken) { var urls = await _context.workOrderAttachments .AsNoTracking() .Where(a => a.WorkorderId == workOrderId && a.IsDeleted != true && a.Attachments != null) .Select(a => a.Attachments!) .ToListAsync(cancellationToken); return urls; } public async Task> ListActiveVendorMediaContentTypesAsync( int workOrderId, CancellationToken cancellationToken) { // Uplift evidence also records the latest completion id in ReplacesDocumentId, so only // a newer completion version supersedes a document. return await _context.VendorCompletionDocuments .AsNoTracking() .Where(document => document.WorkOrderId == workOrderId && (document.IsDeleted == null || document.IsDeleted == false) && !_context.VendorCompletionDocuments.Any(newer => newer.ReplacesDocumentId == document.Id && newer.Purpose == "Completion" && (newer.IsDeleted == null || newer.IsDeleted == false))) .Select(document => document.ContentType) .ToListAsync(cancellationToken); } public void SetExpectedWorkOrderVersion(WorkOrder workOrder, byte[] version) => _context.Entry(workOrder).Property(w => w.RowVersion).OriginalValue = version; public void MarkWorkOrderModified(WorkOrder workOrder) { // Force a WO update so the RowVersion concurrency token is enforced when only // attachment rows change (category-only Extra mutations). var entry = _context.Entry(workOrder); if (entry.State == EntityState.Unchanged) entry.Property(w => w.Attachments).IsModified = true; } public Task SaveAsync(CancellationToken cancellationToken) => _context.SaveChangesAsync(cancellationToken); } }