using System.Net;
using System.Net.Sockets;
using GmRelay.DiscordBot.Infrastructure.Health;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging.Abstractions;

namespace GmRelay.Bot.Tests.Infrastructure.Health;

public sealed class DiscordHealthCheckHostedServiceTests : IDisposable
{
    private readonly DiscordHealthCheckHostedService _service;
    private readonly int _port;

    public DiscordHealthCheckHostedServiceTests()
    {
        _port = GetAvailablePort();
        var config = new ConfigurationBuilder()
            .AddInMemoryCollection(new Dictionary<string, string?>
            {
                ["HealthCheck:Prefix"] = $"http://localhost:{_port}/"
            })
            .Build();

        _service = new DiscordHealthCheckHostedService(
            NullLogger<DiscordHealthCheckHostedService>.Instance,
            config);
    }

    public void Dispose()
    {
        _service.StopAsync(CancellationToken.None).Wait(TimeSpan.FromSeconds(5));
    }

    [Fact]
    public async Task HealthEndpoint_ShouldReturn200_WhenServiceIsRunning()
    {
        await _service.StartAsync(CancellationToken.None);

        using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(5) };
        var response = await client.GetAsync($"http://localhost:{_port}/health");

        Assert.Equal(HttpStatusCode.OK, response.StatusCode);
    }

    private static int GetAvailablePort()
    {
        var listener = new TcpListener(IPAddress.Loopback, 0);
        listener.Start();
        var port = ((IPEndPoint)listener.LocalEndpoint).Port;
        listener.Stop();
        return port;
    }
}
