using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

public class ClinicalAlertConfiguration : IEntityTypeConfiguration<ClinicalAlert>
{
    private static readonly JsonSerializerOptions JsonOptions = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase
    };

    public void Configure(EntityTypeBuilder<ClinicalAlert> builder)
    {
        builder.ToTable("clinical_alerts", t =>
        {
            t.HasCheckConstraint("chk_clinical_alerts_severity",
                "severity IN ('WARNING', 'CRITICAL')");
            t.HasCheckConstraint("chk_clinical_alerts_status",
                "status IN ('OPEN', 'ACKNOWLEDGED', 'RESOLVED', 'ESCALATED')");
            t.HasCheckConstraint("chk_clinical_alerts_alert_type",
                "alert_type IN (" +
                "'SEPSIS_WARNING', " +
                "'CRITICAL_HEART_RATE', 'CRITICAL_TEMP_C', 'CRITICAL_POTASSIUM_MEQ_L', " +
                "'CRITICAL_SPO2', 'CRITICAL_RESP_RATE', 'CRITICAL_WBC_K_UL', " +
                "'CRITICAL_SYSTOLIC_BP', 'CRITICAL_DIASTOLIC_BP', 'CRITICAL_LACTATE_MMOL_L', " +
                "'CRITICAL_AVPU', 'CRITICAL_GLUCOSE_MG_DL', " +
                "'CRITICAL_PAO2_MMHG', 'CRITICAL_PLATELET_K_UL', " +
                "'CRITICAL_BILIRUBIN_MG_DL', 'CRITICAL_CREATININE_MG_DL', " +
                "'WARNING_HEART_RATE', 'WARNING_TEMP_C', 'WARNING_POTASSIUM_MEQ_L', " +
                "'WARNING_SPO2', 'WARNING_RESP_RATE', 'WARNING_WBC_K_UL', " +
                "'WARNING_SYSTOLIC_BP', 'WARNING_DIASTOLIC_BP', 'WARNING_LACTATE_MMOL_L', " +
                "'WARNING_GLUCOSE_MG_DL', " +
                "'WARNING_PAO2_MMHG', 'WARNING_PLATELET_K_UL', " +
                "'WARNING_BILIRUBIN_MG_DL', 'WARNING_CREATININE_MG_DL', " +
                "'NEWS2_WARNING', 'NEWS2_EMERGENCY', " +
                "'RAPID_DETERIORATION', 'QSOFA_WARNING', 'QSOFA_SCREEN', " +
                "'GCS_CRITICAL', 'GCS_WARNING', " +
                "'SOFA_SEPSIS', 'SOFA_WARNING')");
        });
        builder.HasKey(a => a.Id);
        builder.Property(a => a.Id).HasColumnName("id").HasDefaultValueSql("gen_random_uuid()");
        builder.Property(a => a.EncounterId).HasColumnName("encounter_id");
        builder.Property(a => a.PatientId).HasColumnName("patient_id");
        builder.Property(a => a.ObservationId).HasColumnName("observation_id");
        builder.Property(a => a.AlertType)
            .HasColumnName("alert_type")
            .HasMaxLength(50)
            .HasConversion(
                v => v.ToDbString(),
                v => AlertTypeExtensions.FromDbString(v))
            .IsRequired();
        builder.Property(a => a.Severity)
            .HasColumnName("severity")
            .HasMaxLength(20)
            .HasConversion(
                v => v.ToDbString(),
                v => AlertSeverityExtensions.FromDbString(v))
            .IsRequired();
        builder.Property(a => a.Details).HasColumnName("details").IsRequired();
        builder.Property(a => a.ObservationCode).HasColumnName("observation_code").HasMaxLength(50);
        builder.Property(a => a.Status)
            .HasColumnName("status")
            .HasMaxLength(20)
            .HasConversion(
                v => v.ToDbString(),
                v => AlertStatusExtensions.FromDbString(v))
            .HasDefaultValueSql("'OPEN'")
            .HasSentinel((AlertStatus)(-1));
        builder.Property(a => a.AcknowledgedAt).HasColumnName("acknowledged_at");
        builder.Property(a => a.AcknowledgedBy).HasColumnName("acknowledged_by").HasMaxLength(200);
        builder.Property(a => a.ResolvedAt).HasColumnName("resolved_at");
        builder.Property(a => a.ClientAlertId).HasColumnName("client_alert_id");
        builder.Property(a => a.SyncedFromGateway).HasColumnName("synced_from_gateway").HasDefaultValue(false);
        builder.Property(a => a.TriggeredAt).HasColumnName("triggered_at").HasDefaultValueSql("NOW()");
        builder.Property(a => a.FeedbackReceived).HasColumnName("feedback_received")
            .HasDefaultValue(false);
        builder.Property(a => a.Explanation)
            .HasColumnName("explanation")
            .HasColumnType("jsonb")
            .HasConversion(
                v => v == null ? null : JsonSerializer.Serialize(v, JsonOptions),
                v => string.IsNullOrEmpty(v) ? null : JsonSerializer.Deserialize<AlertExplanation>(v, JsonOptions)!);

        builder.HasOne(a => a.Encounter)
            .WithMany(e => e.Alerts)
            .HasForeignKey(a => a.EncounterId)
            .OnDelete(DeleteBehavior.Restrict);

        builder.HasIndex(a => new { a.EncounterId, a.TriggeredAt });
        builder.HasIndex(a => new { a.PatientId, a.TriggeredAt });
        builder.HasIndex(a => new { a.Severity, a.TriggeredAt })
            .HasFilter("status = 'OPEN'");
        builder.HasIndex(a => new { a.EncounterId, a.AlertType, a.ObservationCode })
            .HasFilter("status IN ('OPEN', 'ESCALATED')");
        builder.HasIndex(a => a.ClientAlertId)
            .IsUnique()
            .HasFilter("client_alert_id IS NOT NULL");
    }
}
