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

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

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

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

        _fixture.SimulationClientFactory.HangOnCreate = false;
        _fixture.SimulationClientFactory.FailOnCreate = false;

        _client.DefaultRequestHeaders.Remove("X-Test-Role");
        _client.DefaultRequestHeaders.Remove("X-Test-User-Id");
        _client.AsAdmin();
    }

    public Task DisposeAsync() => Task.CompletedTask;

    [Fact]
    public async Task Config_ReturnsEnabledFalse_WhenDisabled()
    {
        using var factory = _fixture.WithWebHostBuilder(builder =>
        {
            builder.ConfigureAppConfiguration((_, config) =>
            {
                config.AddInMemoryCollection(new Dictionary<string, string?>
                {
                    ["Simulation:Enabled"] = "false",
                });
            });
        });

        var client = factory.CreateClient();
        client.AsAdmin();

        var resp = await client.GetAsync("/api/v1/simulation/config");
        resp.StatusCode.Should().Be(HttpStatusCode.OK);

        var body = await resp.Content.ReadFromJsonAsync<JsonElement>();
        body.GetProperty("data").GetProperty("enabled").GetBoolean().Should().BeFalse();
    }

    [Fact]
    public async Task Scenarios_WhenDisabled_Returns404()
    {
        using var factory = _fixture.WithWebHostBuilder(builder =>
        {
            builder.ConfigureAppConfiguration((_, config) =>
            {
                config.AddInMemoryCollection(new Dictionary<string, string?>
                {
                    ["Simulation:Enabled"] = "false",
                });
            });
        });

        var client = factory.CreateClient();
        client.AsAdmin();

        var resp = await client.GetAsync("/api/v1/simulation/scenarios");
        resp.StatusCode.Should().Be(HttpStatusCode.NotFound);
    }

    [Fact]
    public async Task Scenarios_AsNurse_Returns200()
    {
        _client.AsNurse();

        var resp = await _client.GetAsync("/api/v1/simulation/scenarios");
        resp.StatusCode.Should().Be(HttpStatusCode.OK);

        var body = await resp.Content.ReadFromJsonAsync<JsonElement>();
        var items = body.GetProperty("data");
        items.GetArrayLength().Should().BeGreaterThan(0);
        items[0].GetProperty("id").GetString().Should().Be("minimal-sim-01");
    }

    [Fact]
    public async Task StartRun_AsIntegrationRole_Returns403()
    {
        _client.AsIntegration();

        var resp = await _client.PostAsJsonAsync("/api/v1/simulation/runs", new
        {
            scenarioId = "minimal-sim-01",
            speed = 600
        });

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

    [Fact]
    public async Task StartRun_WritesAuditLog()
    {
        _client.AsPhysician();

        var resp = await _client.PostAsJsonAsync("/api/v1/simulation/runs", new
        {
            scenarioId = "minimal-sim-01",
            speed = 600
        });

        resp.StatusCode.Should().Be(HttpStatusCode.Created);
        var body = await resp.Content.ReadFromJsonAsync<JsonElement>();
        var runId = body.GetProperty("data").GetProperty("runId").GetGuid();

        using var scope = _fixture.Services.CreateScope();
        var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
        var audit = await db.ClinicalAuditLogs
            .Where(a => a.Action == AuditAction.SimulationRunStarted && a.EntityId == runId)
            .SingleOrDefaultAsync();

        audit.Should().NotBeNull();
        audit!.EntityType.Should().Be("SimulationRun");
    }

    [Fact]
    public async Task Config_WhenEnabled_ReturnsLimits()
    {
        _client.AsNurse();

        var resp = await _client.GetAsync("/api/v1/simulation/config");
        resp.StatusCode.Should().Be(HttpStatusCode.OK);

        var body = await resp.Content.ReadFromJsonAsync<JsonElement>();
        var data = body.GetProperty("data");
        data.GetProperty("enabled").GetBoolean().Should().BeTrue();
        data.GetProperty("maxSpeed").GetDouble().Should().Be(600);
        data.GetProperty("maxConcurrentRuns").GetInt32().Should().Be(2);
    }
}
