using System.Net;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using ZB.MOM.WW.Health;

namespace ZB.MOM.WW.Health.Tests;

/// <summary>
/// Verifies <see cref="ActiveNodeGateExtensions.RequireActiveNode"/>: a decorated endpoint serves
/// normally (200) when the resolved <see cref="IActiveNodeGate"/> reports the node active, and
/// returns 503 with a <c>Retry-After</c> header when the node is a standby.
/// </summary>
public sealed class ActiveNodeGateTests
{
    private sealed class FakeActiveNodeGate : IActiveNodeGate
    {
        public bool IsActiveNode { get; set; }
    }

    private static async Task<HttpResponseMessage> CallAsync(bool isActive)
    {
        var builder = WebApplication.CreateBuilder();
        builder.WebHost.UseTestServer();
        builder.Services.AddSingleton<IActiveNodeGate>(new FakeActiveNodeGate { IsActiveNode = isActive });

        await using var app = builder.Build();
        app.MapGet("/x", () => "ok").RequireActiveNode();
        await app.StartAsync();

        var client = app.GetTestClient();
        return await client.GetAsync("/x");
    }

    [Fact]
    public async Task ActiveNode_Returns200()
    {
        var response = await CallAsync(isActive: true);

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        Assert.Equal("ok", await response.Content.ReadAsStringAsync());
    }

    [Fact]
    public async Task StandbyNode_Returns503_WithRetryAfterHeader()
    {
        var response = await CallAsync(isActive: false);

        Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
        Assert.True(
            response.Headers.Contains("Retry-After"),
            "Standby response must carry a Retry-After header.");
    }

    [Fact]
    public async Task NoGateRegistered_AllowsRequest()
    {
        // When no IActiveNodeGate is registered (non-clustered host / tests), the endpoint is served.
        var builder = WebApplication.CreateBuilder();
        builder.WebHost.UseTestServer();

        await using var app = builder.Build();
        app.MapGet("/x", () => "ok").RequireActiveNode();
        await app.StartAsync();

        var response = await app.GetTestClient().GetAsync("/x");
        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
    }
}
