using System.Net;
using Flurl;
using InnovEnergy.Lib.Utils;

namespace InnovEnergy.Lib.WebServer;

public delegate HttpResponse? HttpHandler(HttpRequest httpRequest);

public static class WebServer
{

    public static void ServeOnLocalHost(Int32 port, params Func<HttpRequest, HttpResponse?>[] handlers)
    {
        Serve($"http://localhost:{port}/", handlers);
    }

    public static void Serve(this String prefix, params Func<HttpRequest, HttpResponse?>[] handlers)
    {
        Console.WriteLine("Server started on " + prefix);

        var listener = new HttpListener();
        listener.Prefixes.Add(prefix);
        listener.Start();

        var handlers404 = handlers
                         .Concat(Default.HttpResponse)
                         .ToArray();

        while (true)
        {
            try
            {
                var context = listener.GetContext();
                var request = context.ConvertRequest();

                var response = handlers404
                              .Select(f => f(request))
                              .SkipWhile(r => r == null)
                              .First()!;

                context.SendResponse(response);
            }
            catch
            {
                // ignored
            }
        }

        // ReSharper disable once FunctionNeverReturns
    }

    private static void SendResponse(this HttpListenerContext context, HttpResponse r)
    {
        var response = context.Response;
        var cookieCollection = response.Cookies;

        foreach (var cookie in r.Cookies)
            cookieCollection.Add(cookie);

        foreach (var (name, value) in r.Headers)
            response.Headers.Add(name, value);

        response.StatusCode = r.StatusCode;
        response.ContentType = r.ContentType.AsString();

        var cont = r.Content.ToArray();
        response.OutputStream.Write(cont);

        response.Close();
    }

    private static HttpRequest ConvertRequest(this HttpListenerContext context)
    {
        var req = context.Request;

        return new HttpRequest
        {
            Method  = req.ParseMethod(),
            Headers = req.ParseHeaders(),
            Cookies = req.Cookies,
            Url     = Url.Parse(req.Url?.OriginalString ?? ""),
            Content = req.InputStream.AsEnumerable(),
        };
    }
}