using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Nexus.Api.Controllers;
using Xunit;

namespace Nexus.Api.Tests;

public sealed class HealthControllerTests
{
    [Fact]
    public async Task Ready_Returns200_WhenRequiredChecksAreHealthy()
    {
        using var provider = BuildProvider(HealthCheckResult.Healthy());
        var controller = new HealthController(
            runtime: null!,
            provider.GetRequiredService<HealthCheckService>());

        var result = await controller.Ready(CancellationToken.None);

        Assert.Equal(StatusCodes.Status200OK, Assert.IsAssignableFrom<IStatusCodeHttpResult>(result).StatusCode);
    }

    [Fact]
    public async Task Ready_Returns503_WhenRequiredCheckIsUnhealthy()
    {
        using var provider = BuildProvider(HealthCheckResult.Unhealthy("database unavailable"));
        var controller = new HealthController(
            runtime: null!,
            provider.GetRequiredService<HealthCheckService>());

        var result = await controller.Ready(CancellationToken.None);

        Assert.Equal(
            StatusCodes.Status503ServiceUnavailable,
            Assert.IsAssignableFrom<IStatusCodeHttpResult>(result).StatusCode);
    }

    [Fact]
    public async Task Ready_Returns503_WhenPostgreSqlCannotBeReached()
    {
        var services = new ServiceCollection();
        services.AddLogging();
        services.AddHealthChecks()
            .AddNpgSql(
                "Host=127.0.0.1;Port=1;Database=nexus;Username=nexus;Password=unused;Timeout=1;Command Timeout=1",
                name: "postgresql",
                tags: ["database", "ready"]);
        using var provider = services.BuildServiceProvider();
        var controller = new HealthController(
            runtime: null!,
            provider.GetRequiredService<HealthCheckService>());

        var result = await controller.Ready(CancellationToken.None);

        Assert.Equal(
            StatusCodes.Status503ServiceUnavailable,
            Assert.IsAssignableFrom<IStatusCodeHttpResult>(result).StatusCode);
    }

    private static ServiceProvider BuildProvider(HealthCheckResult result)
    {
        var services = new ServiceCollection();
        services.AddLogging();
        services.AddHealthChecks()
            .AddCheck("required", () => result, tags: ["ready"]);
        return services.BuildServiceProvider();
    }
}
