using System.Net;
using System.Text;
using Inspectron.Epson.PrintServer.ConfigurationSources;

namespace EpsonPrintService;

public class SimpleHttpServer
{
    private readonly HttpListener _listener;
    private readonly Func<EpsonPrintServiceConfiguration?> _getConfig;
    private readonly Func<bool> _getIsRunning;

    public SimpleHttpServer(Func<EpsonPrintServiceConfiguration?> getConfig, Func<bool> getIsRunning)
    {
        _listener = new HttpListener();
        _listener.Prefixes.Add("http://+:80/");
        _getConfig = getConfig;
        _getIsRunning = getIsRunning;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        _listener.Start();
        Console.WriteLine("Web UI listening on http://+:80/");

        try
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                var context = await _listener.GetContextAsync();
                _ = Task.Run(() => HandleRequestAsync(context), cancellationToken);
            }
        }
        catch (HttpListenerException) when (cancellationToken.IsCancellationRequested)
        {
            // Expected on shutdown
        }
        finally
        {
            _listener.Stop();
        }
    }

    private async Task HandleRequestAsync(HttpListenerContext context)
    {
        try
        {
            var request = context.Request;
            var response = context.Response;
            var path = request.Url?.AbsolutePath ?? "/";
            var method = request.HttpMethod;

            string html;

            if (method == "GET" && path == "/")
            {
                html = await BuildIndexPageAsync();
            }
            else if (method == "POST" && path == "/update-key")
            {
                html = await HandleUpdateKeyAsync();
            }
            else
            {
                response.StatusCode = 404;
                html = "<html><body><h1>Not Found</h1></body></html>";
            }

            var buffer = Encoding.UTF8.GetBytes(html);
            response.ContentType = "text/html; charset=utf-8";
            response.ContentLength64 = buffer.Length;
            await response.OutputStream.WriteAsync(buffer);
            response.Close();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"HTTP error: {ex.Message}");
            try { context.Response.Close(); } catch { }
        }
    }

    private async Task<string> BuildIndexPageAsync()
    {
        var usbResult = await UsbKeyScanner.ScanForKeyAsync();
        return HtmlPageBuilder.BuildConfigPage(_getConfig(), _getIsRunning(), usbResult);
    }

    private async Task<string> HandleUpdateKeyAsync()
    {
        var usbResult = await UsbKeyScanner.ScanForKeyAsync();

        if (!usbResult.Found || usbResult.Base64Content == null)
        {
            return HtmlPageBuilder.BuildConfigPage(
                _getConfig(), _getIsRunning(), usbResult,
                errorMessage: "No valid USB key found. Please insert a USB drive and try again.");
        }

        // Validate again
        var validation = ConfigurationLoader.TryLoadFromBase64(usbResult.Base64Content);
        if (!validation.Success)
        {
            return HtmlPageBuilder.BuildConfigPage(
                _getConfig(), _getIsRunning(), usbResult,
                errorMessage: $"Key validation failed: {validation.Error}");
        }

        // Write config file
        try
        {
            var configPath = ConfigurationPaths.GetConfigPath();
            var configDir = Path.GetDirectoryName(configPath);
            if (!string.IsNullOrEmpty(configDir) && !Directory.Exists(configDir))
                Directory.CreateDirectory(configDir);

            await File.WriteAllTextAsync(configPath, usbResult.Base64Content);
            Console.WriteLine($"Configuration updated at {configPath}");
        }
        catch (Exception ex)
        {
            return HtmlPageBuilder.BuildConfigPage(
                _getConfig(), _getIsRunning(), usbResult,
                errorMessage: $"Failed to write configuration: {ex.Message}");
        }

        // Schedule exit so systemd restarts us with new config
        _ = Task.Run(async () =>
        {
            await Task.Delay(500);
            Console.WriteLine("Exiting for restart with new configuration...");
            Environment.Exit(0);
        });

        return HtmlPageBuilder.BuildSuccessPage(validation.Config!);
    }
}
