using System.Net;
using System.Net.Http.Json;
using System.Text.Json;
using FluentAssertions;
using Microsoft.Extensions.DependencyInjection;
using StackExchange.Redis;

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

    public QsofaCurrentTests(ApiFixture fixture)
    {
        _fixture = fixture;
        _client = fixture.CreateClient();
    }

    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-QSOFA-API", FirstName = "qSOFA", LastName = "Api",
            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. qSOFA", AdmittedAt = DateTimeOffset.UtcNow,
            CreatedAt = DateTimeOffset.UtcNow
        };
        db.Patients.Add(patient);
        db.Encounters.Add(encounter);
        await db.SaveChangesAsync();

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

        var redis = scope.ServiceProvider.GetRequiredService<IConnectionMultiplexer>();
        var cache = redis.GetDatabase();
        foreach (var key in QsofaCalculator.AllCriterionKeys(_encounterId))
            await cache.KeyDeleteAsync(key);
    }

    public Task DisposeAsync() => Task.CompletedTask;

    [Fact]
    public async Task Current_AfterBaselineVitals_ReturnsZeroCriteria()
    {
        using var scope = _fixture.Services.CreateScope();
        var detector = scope.ServiceProvider.GetRequiredService<QsofaDetector>();
        await detector.ProcessObservationAsync(_encounterId, _patientId, "RESP_RATE", 16m);

        var resp = await _client.GetAsync($"/api/v1/encounters/{_encounterId}/qsofa/current");
        resp.StatusCode.Should().Be(HttpStatusCode.OK);

        var body = await resp.Content.ReadFromJsonAsync<JsonDocument>();
        body!.RootElement.GetProperty("data").GetProperty("activeCriteria").GetInt32()
            .Should().Be(0);
    }

    [Fact]
    public async Task Current_AfterTwoCriteriaMet_ReturnsTwo()
    {
        using var scope = _fixture.Services.CreateScope();
        var detector = scope.ServiceProvider.GetRequiredService<QsofaDetector>();
        await detector.ProcessObservationAsync(_encounterId, _patientId, "RESP_RATE", 24m);
        await detector.ProcessObservationAsync(_encounterId, _patientId, "SYSTOLIC_BP", 95m);

        var resp = await _client.GetAsync($"/api/v1/encounters/{_encounterId}/qsofa/current");
        resp.StatusCode.Should().Be(HttpStatusCode.OK);

        var data = (await resp.Content.ReadFromJsonAsync<JsonDocument>())!
            .RootElement.GetProperty("data");
        data.GetProperty("activeCriteria").GetInt32().Should().Be(2);
        data.GetProperty("criteria").GetProperty("respRate").GetDecimal().Should().Be(24m);
        data.GetProperty("criteria").GetProperty("systolicBp").GetDecimal().Should().Be(95m);
    }

    [Fact]
    public async Task Current_UnknownEncounter_Returns404()
    {
        var resp = await _client.GetAsync($"/api/v1/encounters/{Guid.NewGuid()}/qsofa/current");
        resp.StatusCode.Should().Be(HttpStatusCode.NotFound);
    }
}
