using System.Net;

namespace GmRelay.DiscordBot.Infrastructure.Health;

public sealed class DiscordHealthCheckHostedService : IHostedService
{
    private readonly ILogger<DiscordHealthCheckHostedService> _logger;
    private readonly string _prefix;
    private HttpListener? _listener;
    private CancellationTokenSource? _cts;
    private Task? _listenerTask;

    public DiscordHealthCheckHostedService(
        ILogger<DiscordHealthCheckHostedService> logger,
        IConfiguration configuration)
    {
        _logger = logger;
        _prefix = configuration.GetValue("HealthCheck:Prefix", "http://+:8082/")!;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _cts = new CancellationTokenSource();
        _listener = new HttpListener();
        _listener.Prefixes.Add(_prefix);
        _listener.Start();

        _logger.LogInformation("Discord health check server started on {Prefix}", _prefix);

        _listenerTask = Task.Run(async () => await ListenAsync(_cts.Token), cancellationToken);

        return Task.CompletedTask;
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        _cts?.Cancel();
        _listener?.Stop();

        if (_listenerTask != null)
        {
            await Task.WhenAny(_listenerTask, Task.Delay(TimeSpan.FromSeconds(5), cancellationToken));
        }

        _listener?.Close();
        _logger.LogInformation("Discord health check server stopped");
    }

    private async Task ListenAsync(CancellationToken cancellationToken)
    {
        while (_listener?.IsListening == true && !cancellationToken.IsCancellationRequested)
        {
            try
            {
                var context = await _listener.GetContextAsync();
                _ = Task.Run(() => HandleRequestAsync(context), cancellationToken);
            }
            catch (HttpListenerException) when (cancellationToken.IsCancellationRequested)
            {
                break;
            }
            catch (ObjectDisposedException)
            {
                break;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error in Discord health check listener");
            }
        }
    }

    private async Task HandleRequestAsync(HttpListenerContext context)
    {
        var response = context.Response;
        try
        {
            var request = context.Request;

            if (request.Url?.AbsolutePath == "/health")
            {
                response.StatusCode = (int)HttpStatusCode.OK;
                response.ContentType = "application/json";
                var body = "{\"status\":\"healthy\"}"u8.ToArray();
                await response.OutputStream.WriteAsync(body);
            }
            else
            {
                response.StatusCode = (int)HttpStatusCode.NotFound;
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error handling Discord health check request");
        }
        finally
        {
            response.Close();
        }
    }
}
