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

[Collection("GatewayIntegration")]
public class WardGatewayLocalPathTests : IAsyncLifetime
{
    private readonly GatewayApiFixture _fixture;
    private readonly HttpClient _client;
    private Guid _encounterId;

    public WardGatewayLocalPathTests(GatewayApiFixture fixture)
    {
        _fixture = fixture;
        _client = fixture.CreateClient();
    }

    public async Task InitializeAsync()
    {
        (_, _encounterId) = await GatewayTestSeeder.SeedActiveEncounterAsync(_fixture.Services);
    }

    public Task DisposeAsync() => Task.CompletedTask;

    [Fact]
    public async Task CriticalObservation_CreatesAlertLocally()
    {
        var resp = await _client.PostAsJsonAsync(
            $"/api/v1/encounters/{_encounterId}/observations",
            new
            {
                observationCode = "HEART_RATE",
                value = 160,
                unit = "bpm",
                source = "DEVICE",
                recordedAt = DateTimeOffset.UtcNow,
                idempotencyKey = Guid.NewGuid().ToString()
            });

        resp.StatusCode.Should().Be(HttpStatusCode.Created);

        using var scope = _fixture.Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<GatewayDbContext>();
        (await db.ClinicalAlerts.CountAsync()).Should().BeGreaterThan(0);
        (await db.BufferedSyncItems.CountAsync(b => !b.Synced)).Should().BeGreaterThan(0);
    }

    [Fact]
    public async Task DuplicateIdempotencyKey_ReturnsExisting()
    {
        var key = Guid.NewGuid().ToString();
        var body = new
        {
            observationCode = "HEART_RATE",
            value = 80,
            unit = "bpm",
            source = "DEVICE",
            recordedAt = DateTimeOffset.UtcNow,
            idempotencyKey = key
        };
        await _client.PostAsJsonAsync($"/api/v1/encounters/{_encounterId}/observations", body);
        var dup = await _client.PostAsJsonAsync($"/api/v1/encounters/{_encounterId}/observations", body);
        dup.StatusCode.Should().Be(HttpStatusCode.OK);

        var json = await dup.Content.ReadFromJsonAsync<JsonDocument>();
        json!.RootElement.GetProperty("data").GetProperty("duplicate").GetBoolean().Should().BeTrue();
    }

    [Fact]
    public async Task Acknowledge_WritesBufferedAck()
    {
        await _client.PostAsJsonAsync(
            $"/api/v1/encounters/{_encounterId}/observations",
            new
            {
                observationCode = "HEART_RATE",
                value = 160,
                unit = "bpm",
                source = "DEVICE",
                recordedAt = DateTimeOffset.UtcNow,
                idempotencyKey = Guid.NewGuid().ToString()
            });

        var alertsResp = await _client.GetAsync($"/api/v1/encounters/{_encounterId}/alerts");
        alertsResp.StatusCode.Should().Be(HttpStatusCode.OK);
        var alertsDoc = await alertsResp.Content.ReadFromJsonAsync<JsonDocument>();
        var alertId = alertsDoc!.RootElement
            .GetProperty("data").GetProperty("items")[0].GetProperty("id").GetGuid();

        var ackResp = await _client.PostAsJsonAsync(
            $"/api/v1/alerts/{alertId}/acknowledge",
            new AcknowledgeAlertRequest("Reviewing at bedside."));
        ackResp.StatusCode.Should().Be(HttpStatusCode.OK);

        using var scope = _fixture.Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<GatewayDbContext>();
        (await db.BufferedSyncItems.CountAsync(b =>
            b.ItemType == BufferedSyncItemType.Ack && !b.Synced)).Should().Be(1);
    }

    [Fact]
    public async Task Acknowledge_WithClinicianId_UsesScenarioAttribution()
    {
        await _client.PostAsJsonAsync(
            $"/api/v1/encounters/{_encounterId}/observations",
            new
            {
                observationCode = "HEART_RATE",
                value = 160,
                unit = "bpm",
                source = "DEVICE",
                recordedAt = DateTimeOffset.UtcNow,
                idempotencyKey = Guid.NewGuid().ToString()
            });

        var alertsResp = await _client.GetAsync($"/api/v1/encounters/{_encounterId}/alerts");
        var alertsDoc = await alertsResp.Content.ReadFromJsonAsync<JsonDocument>();
        var alertId = alertsDoc!.RootElement
            .GetProperty("data").GetProperty("items")[0].GetProperty("id").GetGuid();

        var ackResp = await _client.PostAsJsonAsync(
            $"/api/v1/alerts/{alertId}/acknowledge",
            new AcknowledgeAlertRequest("Calcium gluconate ordered.", "RN-Wu"));
        ackResp.StatusCode.Should().Be(HttpStatusCode.OK);

        using var scope = _fixture.Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<GatewayDbContext>();
        var alert = await db.ClinicalAlerts.SingleAsync(a => a.Id == alertId);
        alert.AcknowledgedBy.Should().Be("RN-Wu");

        var bufferedAck = await db.BufferedSyncItems.SingleAsync(b =>
            b.ItemType == BufferedSyncItemType.Ack && !b.Synced);
        bufferedAck.Payload.Should().Contain("RN-Wu");
    }

    [Fact]
    public async Task CentralDown_ReachabilityReportsDegraded()
    {
        await Task.Delay(TimeSpan.FromSeconds(2));

        using var scope = _fixture.Services.CreateScope();
        var reachability = scope.ServiceProvider.GetRequiredService<CentralReachabilityService>();
        reachability.IsCentralReachable.Should().BeFalse();
    }

    [Fact]
    public async Task WarningObservation_CreatesWarningNoPage()
    {
        var resp = await _client.PostAsJsonAsync(
            $"/api/v1/encounters/{_encounterId}/observations",
            new
            {
                observationCode = "HEART_RATE",
                value = 105,
                unit = "bpm",
                source = "DEVICE",
                recordedAt = DateTimeOffset.UtcNow,
                idempotencyKey = Guid.NewGuid().ToString()
            });

        resp.StatusCode.Should().Be(HttpStatusCode.Created);

        using var scope = _fixture.Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<GatewayDbContext>();
        var alert = await db.ClinicalAlerts.SingleAsync();
        alert.Severity.Should().Be(AlertSeverity.Warning);
        alert.AlertType.Should().Be(AlertType.WarningHeartRate);
        alert.Status.Should().Be(AlertStatus.Open);
    }
}
