using Data.SeaHavenIndustries; using Data.SeaHavenIndustries.Enums; using Microsoft.EntityFrameworkCore; using SeaHaven.Services.Interfaces; namespace SeaHaven.Services.Implementation { public class WorkOrderAuditService : IWorkOrderAuditService { private readonly ApplicationDbContext _context; private readonly IWorkOrderFieldLockService _fieldLocks; public WorkOrderAuditService(ApplicationDbContext context, IWorkOrderFieldLockService fieldLocks) { _context = context; _fieldLocks = fieldLocks; } public Task LogStatusChangedAsync(int workOrderId, string? oldStatus, string? newStatus, string? actorId) => LogAsync(workOrderId, AuditActionType.StatusChanged, AuditEventType.Manual, AuditActorType.Dispatcher, "LifecycleStatus", oldStatus, newStatus, actorId); public Task LogAssignmentChangedAsync(int workOrderId, string? oldValue, string? newValue, string? actorId) => LogAsync(workOrderId, AuditActionType.AssignmentChanged, AuditEventType.Manual, AuditActorType.Dispatcher, "AssignTo", oldValue, newValue, actorId); public Task LogSyncRejectedAsync(int workOrderId, string fieldName, string? oldValue, string? newValue) => LogAsync(workOrderId, AuditActionType.SyncRejected, AuditEventType.Sync, AuditActorType.Sync, fieldName, oldValue, newValue); public Task LogWeekRolledAsync(int workOrderId, int oldCarriedOver, int newCarriedOver, string correlationId) => LogAsync( workOrderId, AuditActionType.WeekRolled, AuditEventType.System, AuditActorType.System, "CarriedOver", oldCarriedOver.ToString(), newCarriedOver.ToString(), correlationId: correlationId); public void StageFieldChanged(int workOrderId, string fieldName, string? oldValue, string? newValue, string? actorId, int? dispatchId = null) => StageAudit(workOrderId, AuditActionType.FieldChanged, fieldName, oldValue, newValue, actorId, dispatchId); public void StageStatusChanged(int workOrderId, string? oldStatus, string? newStatus, string? actorId) => StageAudit(workOrderId, AuditActionType.StatusChanged, "LifecycleStatus", oldStatus, newStatus, actorId); public void StageAssignmentChanged(int workOrderId, string? oldValue, string? newValue, string? actorId) => StageAudit(workOrderId, AuditActionType.AssignmentChanged, "AssignTo", oldValue, newValue, actorId); public void StageCreated(int workOrderId, string? actorId, string? woNumber) => StageAudit(workOrderId, AuditActionType.Create, "WorkOrder", null, woNumber, actorId); public async Task LogAsync( int workOrderId, AuditActionType action, AuditEventType eventType, AuditActorType actorType, string fieldName, string? oldValue, string? newValue, string? actorId = null, int? dispatchId = null, string? correlationId = null) { AddAuditEntry(workOrderId, action, eventType, actorType, fieldName, oldValue, newValue, actorId, dispatchId, correlationId); if (eventType == AuditEventType.Manual && (action == AuditActionType.FieldChanged || action == AuditActionType.StatusChanged || action == AuditActionType.AssignmentChanged)) { await _fieldLocks.LockFieldAsync(workOrderId, fieldName, actorId); } await _context.SaveChangesAsync(); } private void StageAudit( int workOrderId, AuditActionType action, string fieldName, string? oldValue, string? newValue, string? actorId, int? dispatchId = null) { AddAuditEntry(workOrderId, action, AuditEventType.Manual, AuditActorType.Dispatcher, fieldName, oldValue, newValue, actorId, dispatchId); StageFieldLock(workOrderId, fieldName, actorId); } private void AddAuditEntry( int workOrderId, AuditActionType action, AuditEventType eventType, AuditActorType actorType, string fieldName, string? oldValue, string? newValue, string? actorId, int? dispatchId = null, string? correlationId = null) { _context.WorkOrderAuditLogs.Add(new WorkOrderAuditLog { WorkOrderId = workOrderId, UserId = actorId, FieldName = fieldName, OldValue = oldValue ?? "", NewValue = newValue ?? "", Action = action.ToString(), EventType = eventType.ToString(), ActorType = actorType.ToString(), DispatchId = dispatchId, CorrelationId = correlationId, CreatedAt = DateTime.UtcNow }); } private void StageFieldLock(int workOrderId, string fieldName, string? userId) { if (_context.WorkOrderFieldLocks.Local.Any(l => l.WorkOrderId == workOrderId && string.Equals(l.FieldName, fieldName, StringComparison.OrdinalIgnoreCase))) return; var existsInDb = _context.WorkOrderFieldLocks.Any(l => l.WorkOrderId == workOrderId && l.FieldName == fieldName); if (existsInDb) return; _context.WorkOrderFieldLocks.Add(new WorkOrderFieldLock { WorkOrderId = workOrderId, FieldName = fieldName, LockedAt = DateTime.UtcNow, LockedByUserId = userId }); } } }