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

/// <summary>
/// Degraded-mode tests — central is unreachable; gateway clinical path remains authoritative locally.
/// </summary>
[Collection("GatewayIntegration")]
public class WardGatewayPartitionTests : IAsyncLifetime
{
    private readonly GatewayApiFixture _fixture;
    private readonly HttpClient _client;
    private Guid _encounterId;

    public WardGatewayPartitionTests(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 Partition_CriticalIngest_CreatesLocalAlertAndBuffer()
    {
        var resp = await _client.PostAsJsonAsync(
            $"/api/v1/encounters/{_encounterId}/observations",
            new
            {
                observationCode = "HEART_RATE",
                value = 160,
                unit = "bpm",
                source = "DEVICE",
                recordedAt = DateTimeOffset.UtcNow,
                idempotencyKey = $"partition-{Guid.NewGuid()}"
            });

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

        using var scope = _fixture.Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<GatewayDbContext>();
        var alerts = await db.ClinicalAlerts.Where(a => a.EncounterId == _encounterId).ToListAsync();
        alerts.Should().ContainSingle();
        alerts[0].Severity.Should().Be(AlertSeverity.Critical);

        (await db.BufferedSyncItems.CountAsync(b => !b.Synced)).Should().BeGreaterThanOrEqualTo(2);
    }

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

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

        var doc = await resp.Content.ReadFromJsonAsync<JsonDocument>();
        doc!.RootElement.GetProperty("data").GetProperty("items").GetArrayLength()
            .Should().BeGreaterThan(0);
    }

    [Fact]
    public async Task Partition_ListActiveEncounters_FromLocalReplica()
    {
        var resp = await _client.GetAsync("/api/v1/encounters?status=ACTIVE&department=ICU");
        resp.StatusCode.Should().Be(HttpStatusCode.OK);

        var doc = await resp.Content.ReadFromJsonAsync<JsonDocument>();
        var items = doc!.RootElement.GetProperty("data").GetProperty("items");
        items.GetArrayLength().Should().BeGreaterThan(0);
        items[0].GetProperty("encounterId").GetGuid().Should().Be(_encounterId);
    }

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

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

        (await _client.PostAsJsonAsync(
            $"/api/v1/alerts/{alertId}/acknowledge",
            new AcknowledgeAlertRequest("Partition ack"))).StatusCode.Should().Be(HttpStatusCode.OK);

        (await _client.PostAsync($"/api/v1/alerts/{alertId}/resolve", null))
            .StatusCode.Should().Be(HttpStatusCode.OK);

        using var scope = _fixture.Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<GatewayDbContext>();
        var alert = await db.ClinicalAlerts.FindAsync(alertId);
        alert!.Status.Should().Be(AlertStatus.Resolved);
        (await db.BufferedSyncItems.CountAsync(b => !b.Synced)).Should().BeGreaterThanOrEqualTo(4);
    }
}
