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

[Collection("Integration")]
public class AlertQualityScenarioAttributionTests : IAsyncLifetime
{
    private readonly ApiFixture _fixture;
    private readonly HttpClient _client;

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

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

    public Task DisposeAsync() => Task.CompletedTask;

    [Fact]
    public async Task AlertQuality_FiltersByScenarioId()
    {
        Guid matchFeedbackId;
        Guid otherFeedbackId;

        using (var scope = _fixture.Services.CreateScope())
        {
            var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();

            var patientA = NewPatient("MRN-SCEN-A");
            var patientB = NewPatient("MRN-SCEN-B");
            var encounterA = NewEncounter(patientA.Id);
            var encounterB = NewEncounter(patientB.Id);
            var alertA = NewAlert(encounterA.Id, patientA.Id, AlertType.News2Warning);
            var alertB = NewAlert(encounterB.Id, patientB.Id, AlertType.News2Emergency);

            db.Patients.AddRange(patientA, patientB);
            db.Encounters.AddRange(encounterA, encounterB);
            db.ClinicalAlerts.AddRange(alertA, alertB);
            db.SimulationRuns.Add(new SimulationRun
            {
                Id = Guid.NewGuid(),
                ScenarioId = "uti-sepsis-elderly-01",
                ScenarioName = "UTI Sepsis",
                Speed = 60,
                Status = SimulationRunStatus.Completed,
                PatientId = patientA.Id,
                EncounterId = encounterA.Id,
                SessionId = "session-b-alert-quality",
                StartedByUserId = "tester",
                StartedAt = DateTimeOffset.UtcNow.AddHours(-1),
                CompletedAt = DateTimeOffset.UtcNow,
            });
            db.SimulationRuns.Add(new SimulationRun
            {
                Id = Guid.NewGuid(),
                ScenarioId = "medication-false-alarm-01",
                ScenarioName = "Med False Alarm",
                Speed = 60,
                Status = SimulationRunStatus.Completed,
                PatientId = patientB.Id,
                EncounterId = encounterB.Id,
                SessionId = "session-b-alert-quality",
                StartedByUserId = "tester",
                StartedAt = DateTimeOffset.UtcNow.AddHours(-1),
                CompletedAt = DateTimeOffset.UtcNow,
            });

            var fbA = new AlertFeedback
            {
                Id = Guid.NewGuid(),
                AlertId = alertA.Id,
                UserId = Guid.NewGuid(),
                FeedbackType = AlertFeedbackType.WouldAct,
                CreatedAt = DateTimeOffset.UtcNow.AddMinutes(-10),
            };
            var fbB = new AlertFeedback
            {
                Id = Guid.NewGuid(),
                AlertId = alertB.Id,
                UserId = Guid.NewGuid(),
                FeedbackType = AlertFeedbackType.FalsePositive,
                CreatedAt = DateTimeOffset.UtcNow.AddMinutes(-5),
            };
            db.AlertFeedbacks.AddRange(fbA, fbB);
            await db.SaveChangesAsync();

            matchFeedbackId = fbA.Id;
            otherFeedbackId = fbB.Id;
        }

        var all = await _client.GetAsync("/api/v1/alerts/quality-metrics/feedback");
        all.StatusCode.Should().Be(HttpStatusCode.OK);
        var allBody = await all.Content.ReadFromJsonAsync<JsonDocument>();
        var allItems = allBody!.RootElement.GetProperty("data").GetProperty("items");
        allItems.GetArrayLength().Should().Be(2);

        var match = allItems.EnumerateArray()
            .Single(e => e.GetProperty("id").GetGuid() == matchFeedbackId);
        match.GetProperty("scenarioId").GetString().Should().Be("uti-sepsis-elderly-01");
        match.GetProperty("sessionId").GetString().Should().Be("session-b-alert-quality");

        var filtered = await _client.GetAsync(
            "/api/v1/alerts/quality-metrics/feedback?scenarioId=uti-sepsis-elderly-01");
        filtered.StatusCode.Should().Be(HttpStatusCode.OK);
        var filteredBody = await filtered.Content.ReadFromJsonAsync<JsonDocument>();
        var filteredItems = filteredBody!.RootElement.GetProperty("data").GetProperty("items");
        filteredItems.GetArrayLength().Should().Be(1);
        filteredItems[0].GetProperty("id").GetGuid().Should().Be(matchFeedbackId);
        filteredItems[0].GetProperty("scenarioId").GetString().Should().Be("uti-sepsis-elderly-01");

        // Other scenario's feedback must not leak into the filter.
        filteredItems.EnumerateArray()
            .Any(e => e.GetProperty("id").GetGuid() == otherFeedbackId)
            .Should().BeFalse();
    }

    private static Patient NewPatient(string mrn) => new()
    {
        Id = Guid.NewGuid(),
        Mrn = mrn,
        FirstName = "Sim",
        LastName = "Patient",
        DateOfBirth = new DateOnly(1980, 1, 1),
        Gender = "F",
        CreatedAt = DateTimeOffset.UtcNow,
        IsSimulated = true,
    };

    private static Encounter NewEncounter(Guid patientId) => new()
    {
        Id = Guid.NewGuid(),
        PatientId = patientId,
        EncounterType = EncounterType.Inpatient,
        Status = EncounterStatus.Active,
        Department = Department.Icu,
        AttendingPhysician = "Dr. Test",
        AdmittedAt = DateTimeOffset.UtcNow,
        CreatedAt = DateTimeOffset.UtcNow,
    };

    private static ClinicalAlert NewAlert(Guid encounterId, Guid patientId, AlertType type) => new()
    {
        Id = Guid.NewGuid(),
        EncounterId = encounterId,
        PatientId = patientId,
        AlertType = type,
        Severity = AlertSeverity.Warning,
        Details = "Test alert",
        Status = AlertStatus.Acknowledged,
        TriggeredAt = DateTimeOffset.UtcNow.AddMinutes(-30),
        AcknowledgedAt = DateTimeOffset.UtcNow.AddMinutes(-20),
        AcknowledgedBy = "nurse",
    };
}
