using FluentAssertions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

[Collection("Integration")]
public class SepsisRefactorTests : IAsyncLifetime
{
    private readonly ApiFixture _fixture;
    private Guid _encounterId;
    private Guid _patientId;

    public SepsisRefactorTests(ApiFixture fixture) => _fixture = fixture;

    public async Task InitializeAsync()
    {
        using var scope = _fixture.Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        await DbResetHelper.ResetAsync(db);

        var patient = new Patient
        {
            Id = Guid.NewGuid(), Mrn = "MRN-REFACTOR-001", FirstName = "Refactor", LastName = "Test",
            DateOfBirth = new DateOnly(1960, 1, 1), Gender = "M",
            CreatedAt = DateTimeOffset.UtcNow
        };
        var encounter = new Encounter
        {
            Id = Guid.NewGuid(), PatientId = patient.Id, EncounterType = EncounterType.Inpatient,
            Status = EncounterStatus.Active, Department = Department.Icu,
            AttendingPhysician = "Dr. Refactor", AdmittedAt = DateTimeOffset.UtcNow,
            CreatedAt = DateTimeOffset.UtcNow
        };
        db.Patients.Add(patient);
        db.Encounters.Add(encounter);
        await db.SaveChangesAsync();

        _patientId = patient.Id;
        _encounterId = encounter.Id;
    }

    public Task DisposeAsync() => Task.CompletedTask;

    [Fact]
    public async Task SirsObservations_NoSepsisWarningAlert()
    {
        using var scope = _fixture.Services.CreateScope();
        var qsofa = scope.ServiceProvider.GetRequiredService<QsofaDetector>();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();

        await qsofa.ProcessObservationAsync(_encounterId, _patientId, "TEMP_C", 39m);
        await qsofa.ProcessObservationAsync(_encounterId, _patientId, "HEART_RATE", 110m);
        await qsofa.ProcessObservationAsync(_encounterId, _patientId, "RESP_RATE", 22m);
        await qsofa.ProcessObservationAsync(_encounterId, _patientId, "WBC_K_UL", 15m);

        (await db.ClinicalAlerts.CountAsync(a => a.AlertType == AlertTypeExtensions.FromDbString("SEPSIS_WARNING")))
            .Should().Be(0);
    }

    [Fact]
    public async Task SofaDelta2_TriggersSepsisBundleCreation()
    {
        using var scope = _fixture.Services.CreateScope();
        var handler = scope.ServiceProvider.GetRequiredService<SepsisAlertHandler>();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();

        var alertId = Guid.NewGuid();
        db.ClinicalAlerts.Add(new ClinicalAlert
        {
            Id = alertId, EncounterId = _encounterId, PatientId = _patientId,
            AlertType = AlertType.SofaSepsis, Severity = AlertSeverity.Critical,
            Details = "SOFA delta +2", Status = AlertStatus.Open,
            TriggeredAt = DateTimeOffset.UtcNow
        });
        await db.SaveChangesAsync();

        await handler.OnSepsisAlertCreatedAsync(
            _encounterId, alertId, AlertType.SofaSepsis, CancellationToken.None);

        (await db.SepsisBundles.CountAsync()).Should().Be(1);
    }

    [Fact]
    public async Task QsofaScreen_DoesNotTriggerBundle()
    {
        using var scope = _fixture.Services.CreateScope();
        var detector = scope.ServiceProvider.GetRequiredService<QsofaDetector>();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();

        await detector.ProcessObservationAsync(_encounterId, _patientId, "RESP_RATE", 24m);
        await detector.ProcessObservationAsync(_encounterId, _patientId, "SYSTOLIC_BP", 95m);

        (await db.SepsisBundles.CountAsync()).Should().Be(0);
    }

    [Fact]
    public async Task QsofaScreen_IsWarningNotCritical()
    {
        using var scope = _fixture.Services.CreateScope();
        var detector = scope.ServiceProvider.GetRequiredService<QsofaDetector>();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();

        await detector.ProcessObservationAsync(_encounterId, _patientId, "RESP_RATE", 24m);
        await detector.ProcessObservationAsync(_encounterId, _patientId, "SYSTOLIC_BP", 95m);

        var alert = await db.ClinicalAlerts.SingleAsync();
        alert.AlertType.Should().Be(AlertType.QsofaScreen);
        alert.Severity.Should().Be(AlertSeverity.Warning);
    }

    [Fact]
    public void QsofaScreen_IsSuppressible()
    {
        AlertType.QsofaScreen.IsSuppressible().Should().BeTrue();
    }

    [Fact]
    public async Task LegacySepsisWarning_StillQueryable()
    {
        using var scope = _fixture.Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        var alertService = scope.ServiceProvider.GetRequiredService<IAlertService>();

        db.ClinicalAlerts.Add(new ClinicalAlert
        {
            Id = Guid.NewGuid(), EncounterId = _encounterId, PatientId = _patientId,
            AlertType = AlertTypeExtensions.FromDbString("SEPSIS_WARNING"), Severity = AlertSeverity.Critical,
            Details = "Legacy SIRS alert", Status = AlertStatus.Resolved,
            TriggeredAt = DateTimeOffset.UtcNow.AddDays(-1)
        });
        await db.SaveChangesAsync();

        var page = await alertService.ListByEncounterAsync(_encounterId, null, 1, 10);
        page.Items.Should().ContainSingle(a => a.AlertType == AlertTypeExtensions.FromDbString("SEPSIS_WARNING"));
    }

    [Fact]
    public void CannotCreateNewSepsisWarning()
    {
        var act = () => AlertCreationGuard.EnsureAllowed(AlertTypeExtensions.FromDbString("SEPSIS_WARNING"));
        act.Should().Throw<InvalidOperationException>()
            .WithMessage("*deprecated*");
    }

    [Fact]
    public async Task SepsisBundleCompliance_StillTracked()
    {
        using var scope = _fixture.Services.CreateScope();
        var handler = scope.ServiceProvider.GetRequiredService<SepsisAlertHandler>();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();

        var alertId = Guid.NewGuid();
        db.ClinicalAlerts.Add(new ClinicalAlert
        {
            Id = alertId, EncounterId = _encounterId, PatientId = _patientId,
            AlertType = AlertType.SofaSepsis, Severity = AlertSeverity.Critical,
            Details = "SOFA delta +2", Status = AlertStatus.Open,
            TriggeredAt = DateTimeOffset.UtcNow
        });
        await db.SaveChangesAsync();
        await handler.OnSepsisAlertCreatedAsync(
            _encounterId, alertId, AlertType.SofaSepsis, CancellationToken.None);

        var bundle = await db.SepsisBundles.SingleAsync();
        bundle.DeadlineAt = DateTimeOffset.UtcNow.AddHours(-1);
        await db.SaveChangesAsync();

        var monitor = new SepsisBundleMonitorService(
            _fixture.Services,
            _fixture.Services.GetRequiredService<ClinicalMetrics>(),
            _fixture.Services.GetRequiredService<ILogger<SepsisBundleMonitorService>>());
        await monitor.ScanOverdueBundlesAsync(CancellationToken.None);

        var updated = await db.SepsisBundles.AsNoTracking().SingleAsync();
        updated.ComplianceStatus.Should().Be(SepsisBundleComplianceStatus.NonCompliant);
    }

    [Fact]
    public async Task QsofaScreen_IncludesLabRecommendation()
    {
        using var scope = _fixture.Services.CreateScope();
        var detector = scope.ServiceProvider.GetRequiredService<QsofaDetector>();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();

        await detector.ProcessObservationAsync(_encounterId, _patientId, "RESP_RATE", 24m);
        await detector.ProcessObservationAsync(_encounterId, _patientId, "SYSTOLIC_BP", 95m);

        var alert = await db.ClinicalAlerts.SingleAsync();
        alert.Details.Should().Contain("order SOFA labs");
    }
}
