using Data.SeaHavenIndustries; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; using SeaHaven.Services.DTOs; using SeaHaven.Services.Interfaces; namespace SeaHaven.Services.Implementation { public class WorkOrderOpsHealthService : IWorkOrderOpsHealthService { private readonly ApplicationDbContext _db; private readonly WorkOrderJobRunStateAccessor _runState; private readonly WorkOrderOpsHealthOptions _options; public WorkOrderOpsHealthService( ApplicationDbContext db, WorkOrderJobRunStateAccessor runState, IOptions options) { _db = db; _runState = runState; _options = options.Value; } public async Task GetHealthAsync(CancellationToken cancellationToken = default) { var since = DateTime.UtcNow.AddHours(-24); var syncRejected = await _db.WorkOrderAuditLogs .CountAsync(l => l.Action == "SyncRejected" && l.CreatedAt >= since, cancellationToken); var fieldLocks = await _db.WorkOrderFieldLocks.CountAsync(cancellationToken); var state = _runState.State; DateTime? ledgerWeekRolled = null; if (await _db.WorkOrderWeekRolledLedgers.AnyAsync(cancellationToken)) { ledgerWeekRolled = await _db.WorkOrderWeekRolledLedgers .MaxAsync(l => (DateTime?)l.ProcessedAt, cancellationToken); } return new WorkOrderOpsHealthDto { LastWeekRolledRunUtc = state.LastWeekRolledRunUtc ?? ledgerWeekRolled, LastPastDueCacheRunUtc = state.LastPastDueCacheRunUtc, LastWeekRolledError = state.LastWeekRolledError, LastPastDueCacheError = state.LastPastDueCacheError, SyncRejectedLast24h = syncRejected, FieldLockCount = fieldLocks, SyncEnabled = _options.SyncEnabled, IngestEnabled = _options.IngestEnabled, LegacyDeprecationEnabled = _options.LegacyDeprecationEnabled, LegacySunsetDate = _options.LegacySunsetDate, CheckedAtUtc = DateTime.UtcNow }; } } /// Options bridged from API configuration for health snapshots. public class WorkOrderOpsHealthOptions { public bool SyncEnabled { get; set; } = true; public bool IngestEnabled { get; set; } = true; public bool LegacyDeprecationEnabled { get; set; } public string? LegacySunsetDate { get; set; } } /// Shared in-memory job run timestamps (API hosted services + ops health). public class WorkOrderJobRunStateAccessor { public WorkOrderJobRunState State { get; } = new(); } public class WorkOrderJobRunState { public DateTime? LastWeekRolledRunUtc { get; set; } public DateTime? LastPastDueCacheRunUtc { get; set; } public string? LastWeekRolledError { get; set; } public string? LastPastDueCacheError { get; set; } } }