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 AlertQualityAnalyticsTests : IAsyncLifetime
{
    private readonly ApiFixture _fixture;
    private readonly HttpClient _client;
    private Guid _alertId;

    public AlertQualityAnalyticsTests(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);

        var patient = new Patient
        {
            Id = Guid.NewGuid(), Mrn = "MRN-QA-001", FirstName = "Quality", LastName = "Analytics",
            DateOfBirth = new DateOnly(1985, 3, 10), Gender = "F", CreatedAt = DateTimeOffset.UtcNow
        };
        var encounter = new Encounter
        {
            Id = Guid.NewGuid(), PatientId = patient.Id, EncounterType = EncounterType.Inpatient,
            Status = EncounterStatus.Active, Department = Department.Icu,
            AttendingPhysician = "Dr. QA", AdmittedAt = DateTimeOffset.UtcNow,
            CreatedAt = DateTimeOffset.UtcNow
        };
        var alert = new ClinicalAlert
        {
            Id = Guid.NewGuid(), EncounterId = encounter.Id, PatientId = patient.Id,
            AlertType = AlertType.News2Warning, Severity = AlertSeverity.Warning,
            Details = "NEWS2 score 6 (MEDIUM).", Status = AlertStatus.Open,
            TriggeredAt = DateTimeOffset.UtcNow.AddMinutes(-30)
        };
        db.Patients.Add(patient);
        db.Encounters.Add(encounter);
        db.ClinicalAlerts.Add(alert);
        await db.SaveChangesAsync();
        _alertId = alert.Id;

        await _client.PostAsJsonAsync(
            $"/api/v1/alerts/{_alertId}/acknowledge",
            new AcknowledgeAlertRequest("Reviewed for QA test."));
    }

    public Task DisposeAsync() => Task.CompletedTask;

    [Theory]
    [InlineData("Useful")]
    [InlineData("TooEarly")]
    [InlineData("TooLate")]
    [InlineData("FalsePositive")]
    [InlineData("MissingContext")]
    [InlineData("WouldAct")]
    public async Task SubmitFeedback_AllTypes_Returns201(string feedbackType)
    {
        await ResetAcknowledgedAlertAsync();

        var resp = await _client.PostAsJsonAsync(
            $"/api/v1/alerts/{_alertId}/feedback",
            new { feedbackType, comment = $"QA {feedbackType}" });

        resp.StatusCode.Should().Be(HttpStatusCode.Created);
        var body = await resp.Content.ReadFromJsonAsync<JsonDocument>();
        body!.RootElement.GetProperty("data").GetProperty("id").GetGuid()
            .Should().NotBe(Guid.Empty);
    }

    [Fact]
    public async Task SubmitFeedback_DuplicateUser_Returns409()
    {
        await ResetAcknowledgedAlertAsync();

        await _client.PostAsJsonAsync(
            $"/api/v1/alerts/{_alertId}/feedback",
            new { feedbackType = "Useful" });

        var resp = await _client.PostAsJsonAsync(
            $"/api/v1/alerts/{_alertId}/feedback",
            new { feedbackType = "FalsePositive" });

        resp.StatusCode.Should().Be(HttpStatusCode.Conflict);
        var body = await resp.Content.ReadFromJsonAsync<JsonDocument>();
        body!.RootElement.GetProperty("error").GetProperty("code").GetString()
            .Should().Be("FEEDBACK_ALREADY_SUBMITTED");
    }

    [Fact]
    public async Task SubmitFeedback_OpenAlert_Returns400()
    {
        using var scope = _fixture.Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        var openAlert = new ClinicalAlert
        {
            Id = Guid.NewGuid(),
            EncounterId = (await db.Encounters.FirstAsync()).Id,
            PatientId = (await db.Patients.FirstAsync()).Id,
            AlertType = AlertType.GcsWarning,
            Severity = AlertSeverity.Warning,
            Details = "Open alert.",
            Status = AlertStatus.Open,
            TriggeredAt = DateTimeOffset.UtcNow
        };
        db.ClinicalAlerts.Add(openAlert);
        await db.SaveChangesAsync();

        var resp = await _client.PostAsJsonAsync(
            $"/api/v1/alerts/{openAlert.Id}/feedback",
            new { feedbackType = "Useful" });

        resp.StatusCode.Should().Be(HttpStatusCode.BadRequest);
    }

    [Fact]
    public async Task SubmitFeedback_WritesAuditLog()
    {
        await ResetAcknowledgedAlertAsync();

        await _client.PostAsJsonAsync(
            $"/api/v1/alerts/{_alertId}/feedback",
            new { feedbackType = "Useful", comment = "audit check" });

        using var scope = _fixture.Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        var logged = await db.ClinicalAuditLogs
            .AnyAsync(l => l.EntityId == _alertId
                        && l.Action == AuditAction.AlertFeedbackSubmitted);
        logged.Should().BeTrue();
    }

    [Fact]
    public async Task QualityMetricsSummary_ReturnsAggregate()
    {
        var resp = await _client.GetAsync("/api/v1/alerts/quality-metrics/summary");
        resp.StatusCode.Should().Be(HttpStatusCode.OK);
        var body = await resp.Content.ReadFromJsonAsync<JsonDocument>();
        body!.RootElement.GetProperty("data").GetProperty("totalAlerts").GetInt32()
            .Should().BeGreaterThanOrEqualTo(0);
    }

    [Fact]
    public async Task QualityMetrics_FilterByType()
    {
        var resp = await _client.GetAsync(
            "/api/v1/alerts/quality-metrics?alertType=NEWS2_WARNING");
        resp.StatusCode.Should().Be(HttpStatusCode.OK);
        var body = await resp.Content.ReadFromJsonAsync<JsonDocument>();
        body!.RootElement.GetProperty("data").GetProperty("items").GetArrayLength()
            .Should().BeGreaterThanOrEqualTo(0);
    }

    private async Task ResetAcknowledgedAlertAsync()
    {
        using var scope = _fixture.Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        var existing = await db.AlertFeedbacks
            .Where(f => f.AlertId == _alertId)
            .ToListAsync();
        db.AlertFeedbacks.RemoveRange(existing);
        await db.SaveChangesAsync();
    }
}