using Microsoft.EntityFrameworkCore; public class LocalWarningEvaluator { private readonly GatewayDbContext _db; private readonly ILogger _logger; public LocalWarningEvaluator(GatewayDbContext db, ILogger logger) { _db = db; _logger = logger; } public async Task TryEvaluateAsync( Guid observationId, Guid encounterId, Guid patientId, string observationCode, decimal value, ThresholdCacheEntry threshold) { if (!IsWarningBreach(value, threshold)) return false; if (IsCriticalBreach(value, threshold)) return false; var alertType = AlertTypeExtensions.WarningFor(observationCode); var clientAlertId = Guid.NewGuid(); var triggeredAt = DateTimeOffset.UtcNow; var details = BuildWarningDetails(observationCode, value, threshold); var exists = await _db.ClinicalAlerts.AnyAsync(a => a.EncounterId == encounterId && a.AlertType == alertType && (a.Status == AlertStatus.Open || a.Status == AlertStatus.Acknowledged)); if (exists) return false; var alert = new LocalClinicalAlert { Id = Guid.NewGuid(), ClientAlertId = clientAlertId, EncounterId = encounterId, PatientId = patientId, ObservationId = observationId, AlertType = alertType, Severity = AlertSeverity.Warning, Details = details, Status = AlertStatus.Open, TriggeredAt = triggeredAt }; _db.ClinicalAlerts.Add(alert); BufferedSyncWriter.Enqueue(_db, BufferedSyncItemType.Alert, new { clientAlertId, encounterId, alertType = alertType.ToDbString(), severity = AlertSeverity.Warning.ToDbString(), details, generatedAt = triggeredAt }, $"alert:{clientAlertId}", encounterId, triggeredAt); _logger.LogInformation( "WARNING alert {AlertId} created locally for encounter {EncounterId}", alert.Id, encounterId); return true; } private static bool IsWarningBreach(decimal value, ThresholdCacheEntry t) => (t.WarningHigh.HasValue && value > t.WarningHigh.Value) || (t.WarningLow.HasValue && value < t.WarningLow.Value); private static bool IsCriticalBreach(decimal value, ThresholdCacheEntry t) => (t.CriticalLow.HasValue && value < t.CriticalLow.Value) || (t.CriticalHigh.HasValue && value > t.CriticalHigh.Value); private static string BuildWarningDetails(string code, decimal value, ThresholdCacheEntry t) => t.WarningHigh.HasValue && value > t.WarningHigh.Value ? $"{code} value {value} is above warning high of {t.WarningHigh}." : $"{code} value {value} is below warning low of {t.WarningLow}."; }