using System.Text.Json; using Microsoft.EntityFrameworkCore; using StackExchange.Redis; public static class DataSeeder { public static async Task SeedAsync(AppDbContext db, IConnectionMultiplexer redis) { if (await db.Patients.AnyAsync()) return; // Two patients var patient1 = new Patient { Id = Guid.NewGuid(), Mrn = "MRN-000001", FirstName = "Jane", LastName = "Smith", DateOfBirth = new DateOnly(1975, 4, 12), Gender = "F", BloodType = BloodType.APositive, Allergies = "Penicillin", EmergencyContactName = "John Smith", EmergencyContactPhone = "555-0101", CreatedAt = DateTimeOffset.UtcNow }; var patient2 = new Patient { Id = Guid.NewGuid(), Mrn = "MRN-000002", FirstName = "Robert", LastName = "Chen", DateOfBirth = new DateOnly(1962, 9, 3), Gender = "M", BloodType = BloodType.ONegative, Allergies = null, EmergencyContactName = "Linda Chen", EmergencyContactPhone = "555-0202", CreatedAt = DateTimeOffset.UtcNow }; db.Patients.AddRange(patient1, patient2); // One active inpatient encounter per patient var encounter1 = new Encounter { Id = Guid.NewGuid(), PatientId = patient1.Id, EncounterType = EncounterType.Inpatient, Status = EncounterStatus.Active, Department = Department.Icu, AttendingPhysician = "Dr. Osei", RoomBed = "ICU-4B", AdmissionReason = "Chest pain, rule out MI", AdmittedAt = DateTimeOffset.UtcNow.AddHours(-6), CreatedAt = DateTimeOffset.UtcNow.AddHours(-6) }; var encounter2 = new Encounter { Id = Guid.NewGuid(), PatientId = patient2.Id, EncounterType = EncounterType.Inpatient, Status = EncounterStatus.Active, Department = Department.GeneralMedicine, AttendingPhysician = "Dr. Patel", RoomBed = "GM-12A", AdmissionReason = "Pneumonia, fever for 3 days", AdmittedAt = DateTimeOffset.UtcNow.AddHours(-12), CreatedAt = DateTimeOffset.UtcNow.AddHours(-12) }; db.Encounters.AddRange(encounter1, encounter2); // Four alert thresholds var thresholds = new List { new() { Id = Guid.NewGuid(), ObservationCode = "HEART_RATE", DisplayName = "Heart Rate", Unit = "bpm", CriticalLow = 30, WarningLow = 50, WarningHigh = 100, CriticalHigh = 150, CreatedAt = DateTimeOffset.UtcNow }, new() { Id = Guid.NewGuid(), ObservationCode = "TEMP_C", DisplayName = "Body Temperature", Unit = "°C", CriticalLow = 35.0m, WarningLow = 36.0m, WarningHigh = 38.3m, CriticalHigh = 40.0m, CreatedAt = DateTimeOffset.UtcNow }, new() { Id = Guid.NewGuid(), ObservationCode = "POTASSIUM_MEQ_L", DisplayName = "Serum Potassium", Unit = "mEq/L", CriticalLow = 2.5m, WarningLow = 3.5m, WarningHigh = 5.0m, CriticalHigh = 6.5m, CreatedAt = DateTimeOffset.UtcNow }, new() { Id = Guid.NewGuid(), ObservationCode = "SPO2", DisplayName = "Oxygen Saturation", Unit = "%", CriticalLow = 88, WarningLow = 92, WarningHigh = null, CriticalHigh = null, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "RESP_RATE", DisplayName = "Respiratory Rate", Unit = "breaths/min", CriticalLow = null, WarningLow = 12m, WarningHigh = 20m, CriticalHigh = 30m, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "WBC_K_UL", DisplayName = "White Blood Cell Count", Unit = "k/µL", CriticalLow = 2.0m, WarningLow = 4.0m, WarningHigh = 12.0m, CriticalHigh = 20.0m, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "SYSTOLIC_BP", DisplayName = "Systolic Blood Pressure", Unit = "mmHg", CriticalLow = 70m, WarningLow = 90m, WarningHigh = 160m, CriticalHigh = 180m, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "DIASTOLIC_BP", DisplayName = "Diastolic Blood Pressure", Unit = "mmHg", CriticalLow = 40m, WarningLow = 60m, WarningHigh = 90m, CriticalHigh = 110m, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "LACTATE_MMOL_L", DisplayName = "Serum Lactate", Unit = "mmol/L", CriticalLow = null, WarningLow = null, WarningHigh = 2.0m, CriticalHigh = 4.0m, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "AVPU", DisplayName = "AVPU Consciousness Level", Unit = "score", CriticalLow = null, WarningLow = null, WarningHigh = null, CriticalHigh = 2m, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "SUPPLEMENTAL_O2", DisplayName = "Supplemental Oxygen", Unit = "flag", CriticalLow = null, WarningLow = null, WarningHigh = null, CriticalHigh = null, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "GLUCOSE_MG_DL", DisplayName = "Blood Glucose", Unit = "mg/dL", CriticalLow = 40m, WarningLow = 70m, WarningHigh = 180m, CriticalHigh = 400m, CreatedAt = DateTimeOffset.UtcNow }, // GCS components — registered for ingestion; thresholds are null (alerting is on computed total in GcsDetector) new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "GCS_EYE", DisplayName = "GCS Eye Response", Unit = "score", CriticalLow = null, WarningLow = null, WarningHigh = null, CriticalHigh = null, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "GCS_VERBAL", DisplayName = "GCS Verbal Response", Unit = "score", CriticalLow = null, WarningLow = null, WarningHigh = null, CriticalHigh = null, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "GCS_MOTOR", DisplayName = "GCS Motor Response", Unit = "score", CriticalLow = null, WarningLow = null, WarningHigh = null, CriticalHigh = null, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "PAO2_MMHG", DisplayName = "Partial Pressure O2 (Arterial)", Unit = "mmHg", CriticalLow = 60m, WarningLow = 80m, WarningHigh = null, CriticalHigh = null, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "FIO2_PCT", DisplayName = "Fraction of Inspired O2", Unit = "%", CriticalLow = null, WarningLow = null, WarningHigh = null, CriticalHigh = null, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "PLATELET_K_UL", DisplayName = "Platelet Count", Unit = "k/µL", CriticalLow = 20m, WarningLow = 50m, WarningHigh = null, CriticalHigh = null, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "BILIRUBIN_MG_DL", DisplayName = "Total Bilirubin", Unit = "mg/dL", CriticalLow = null, WarningLow = null, WarningHigh = 2.0m, CriticalHigh = 6.0m, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "CREATININE_MG_DL", DisplayName = "Serum Creatinine", Unit = "mg/dL", CriticalLow = null, WarningLow = null, WarningHigh = 2.0m, CriticalHigh = 3.5m, CreatedAt = DateTimeOffset.UtcNow }, new AlertThreshold { Id = Guid.NewGuid(), ObservationCode = "URINE_OUTPUT_ML_H", DisplayName = "Urine Output", Unit = "mL/h", CriticalLow = null, WarningLow = null, WarningHigh = null, CriticalHigh = null, CreatedAt = DateTimeOffset.UtcNow }, }; db.AlertThresholds.AddRange(thresholds); // Observations spanning normal, warning, and critical ranges for encounter1 var now = DateTimeOffset.UtcNow; var observations = new List { // Normal heart rate new() { Id = Guid.NewGuid(), EncounterId = encounter1.Id, ObservationCode = "HEART_RATE", Value = 78, Unit = "bpm", Source = ObservationSource.Device, RecordedAt = now.AddMinutes(-30), CreatedAt = now.AddMinutes(-30) }, // Warning heart rate new() { Id = Guid.NewGuid(), EncounterId = encounter1.Id, ObservationCode = "HEART_RATE", Value = 104, Unit = "bpm", Source = ObservationSource.Device, RecordedAt = now.AddMinutes(-15), CreatedAt = now.AddMinutes(-15) }, // Critical potassium (low) new() { Id = Guid.NewGuid(), EncounterId = encounter1.Id, ObservationCode = "POTASSIUM_MEQ_L", Value = 2.3m, Unit = "mEq/L", Source = ObservationSource.Lab, RecordedAt = now.AddMinutes(-10), CreatedAt = now.AddMinutes(-10) }, // Normal SpO2 new() { Id = Guid.NewGuid(), EncounterId = encounter1.Id, ObservationCode = "SPO2", Value = 97, Unit = "%", Source = ObservationSource.Device, RecordedAt = now.AddMinutes(-5), CreatedAt = now.AddMinutes(-5) }, // Normal temp for encounter2 new() { Id = Guid.NewGuid(), EncounterId = encounter2.Id, ObservationCode = "TEMP_C", Value = 37.1m, Unit = "°C", Source = ObservationSource.Manual, RecordedAt = now.AddMinutes(-20), CreatedAt = now.AddMinutes(-20) }, // Blood pressure new() { Id = Guid.NewGuid(), EncounterId = encounter1.Id, ObservationCode = "SYSTOLIC_BP", Value = 128, Unit = "mmHg", Source = ObservationSource.Device, RecordedAt = now.AddMinutes(-25), CreatedAt = now.AddMinutes(-25) }, new() { Id = Guid.NewGuid(), EncounterId = encounter1.Id, ObservationCode = "DIASTOLIC_BP", Value = 82, Unit = "mmHg", Source = ObservationSource.Device, RecordedAt = now.AddMinutes(-25), CreatedAt = now.AddMinutes(-25) }, // Normal lactate new() { Id = Guid.NewGuid(), EncounterId = encounter1.Id, ObservationCode = "LACTATE_MMOL_L", Value = 1.2m, Unit = "mmol/L", Source = ObservationSource.Lab, RecordedAt = now.AddMinutes(-8), CreatedAt = now.AddMinutes(-8) }, // AVPU = Alert (normal consciousness) new() { Id = Guid.NewGuid(), EncounterId = encounter1.Id, ObservationCode = "AVPU", Value = 0, Unit = "score", Source = ObservationSource.Manual, RecordedAt = now.AddMinutes(-28), CreatedAt = now.AddMinutes(-28) }, new() { Id = Guid.NewGuid(), EncounterId = encounter2.Id, ObservationCode = "AVPU", Value = 0, Unit = "score", Source = ObservationSource.Manual, RecordedAt = now.AddMinutes(-18), CreatedAt = now.AddMinutes(-18) }, // Room air (no supplemental oxygen) new() { Id = Guid.NewGuid(), EncounterId = encounter1.Id, ObservationCode = "SUPPLEMENTAL_O2", Value = 0, Unit = "flag", Source = ObservationSource.Manual, RecordedAt = now.AddMinutes(-27), CreatedAt = now.AddMinutes(-27) }, new() { Id = Guid.NewGuid(), EncounterId = encounter2.Id, ObservationCode = "SUPPLEMENTAL_O2", Value = 1, Unit = "flag", Source = ObservationSource.Manual, RecordedAt = now.AddMinutes(-17), CreatedAt = now.AddMinutes(-17) }, }; db.Observations.AddRange(observations); await db.SaveChangesAsync(); // Populate Redis cache with the seeded thresholds var cache = redis.GetDatabase(); foreach (var t in thresholds) { var json = JsonSerializer.Serialize(new { t.ObservationCode, t.CriticalLow, t.WarningLow, t.WarningHigh, t.CriticalHigh }); await cache.StringSetAsync($"threshold:{t.ObservationCode}", json); } } }