using System;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Serilog;
using ZB.MOM.WW.LmxProxy.Host.Configuration;

namespace ZB.MOM.WW.LmxProxy.Host.Status
{
    /// <summary>
    ///     HTTP status server providing an HTML dashboard, JSON API, and health endpoint.
    /// </summary>
    public class StatusWebServer : IDisposable
    {
        private static readonly ILogger Logger = Log.ForContext<StatusWebServer>();

        private readonly WebServerConfiguration _configuration;
        private readonly StatusReportService _statusReportService;
        private HttpListener? _httpListener;
        private CancellationTokenSource? _cancellationTokenSource;
        private Task? _listenerTask;
        private bool _disposed;

        public StatusWebServer(WebServerConfiguration configuration, StatusReportService statusReportService)
        {
            _configuration = configuration;
            _statusReportService = statusReportService;
        }

        public bool Start()
        {
            if (!_configuration.Enabled)
            {
                Logger.Information("Status web server is disabled");
                return true;
            }

            try
            {
                _httpListener = new HttpListener();
                var prefix = _configuration.Prefix ?? $"http://+:{_configuration.Port}/";
                if (!prefix.EndsWith("/"))
                    prefix += "/";

                _httpListener.Prefixes.Add(prefix);
                _httpListener.Start();

                _cancellationTokenSource = new CancellationTokenSource();
                _listenerTask = Task.Run(() => HandleRequestsAsync(_cancellationTokenSource.Token));

                Logger.Information("Status web server started on {Prefix}", prefix);
                return true;
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Failed to start status web server");
                return false;
            }
        }

        public bool Stop()
        {
            if (!_configuration.Enabled || _httpListener == null)
                return true;

            try
            {
                _cancellationTokenSource?.Cancel();

                if (_listenerTask != null)
                {
                    _listenerTask.Wait(TimeSpan.FromSeconds(5));
                }

                _httpListener.Stop();
                _httpListener.Close();

                Logger.Information("Status web server stopped");
                return true;
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Error stopping status web server");
                return false;
            }
        }

        public void Dispose()
        {
            if (_disposed) return;
            _disposed = true;

            Stop();
            _cancellationTokenSource?.Dispose();
            if (_httpListener != null)
            {
                ((IDisposable)_httpListener).Dispose();
            }
        }

        private async Task HandleRequestsAsync(CancellationToken cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested && _httpListener != null && _httpListener.IsListening)
            {
                try
                {
                    var context = await _httpListener.GetContextAsync();
                    _ = Task.Run(() => HandleRequestAsync(context));
                }
                catch (ObjectDisposedException)
                {
                    // Expected during shutdown
                    break;
                }
                catch (HttpListenerException ex) when (ex.ErrorCode == 995)
                {
                    // ERROR_OPERATION_ABORTED — expected during shutdown
                    break;
                }
                catch (Exception ex)
                {
                    Logger.Error(ex, "Error accepting HTTP request");
                    await Task.Delay(1000, cancellationToken).ConfigureAwait(false);
                }
            }
        }

        private async Task HandleRequestAsync(HttpListenerContext context)
        {
            try
            {
                if (context.Request.HttpMethod != "GET")
                {
                    context.Response.StatusCode = 405;
                    await WriteResponseAsync(context.Response, "Method Not Allowed", "text/plain");
                    return;
                }

                var path = context.Request.Url?.AbsolutePath?.ToLowerInvariant() ?? "/";

                switch (path)
                {
                    case "/":
                        await HandleStatusPageAsync(context.Response);
                        break;
                    case "/api/status":
                        await HandleStatusApiAsync(context.Response);
                        break;
                    case "/api/health":
                        await HandleHealthApiAsync(context.Response);
                        break;
                    default:
                        context.Response.StatusCode = 404;
                        await WriteResponseAsync(context.Response, "Not Found", "text/plain");
                        break;
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Error handling HTTP request");
                try
                {
                    context.Response.StatusCode = 500;
                    await WriteResponseAsync(context.Response, "Internal Server Error", "text/plain");
                }
                catch
                {
                    // Ignore errors writing error response
                }
            }
        }

        private async Task HandleStatusPageAsync(HttpListenerResponse response)
        {
            var html = await _statusReportService.GenerateHtmlReportAsync();
            await WriteResponseAsync(response, html, "text/html; charset=utf-8");
        }

        private async Task HandleStatusApiAsync(HttpListenerResponse response)
        {
            var json = await _statusReportService.GenerateJsonReportAsync();
            await WriteResponseAsync(response, json, "application/json; charset=utf-8");
        }

        private async Task HandleHealthApiAsync(HttpListenerResponse response)
        {
            var isHealthy = await _statusReportService.IsHealthyAsync();
            if (isHealthy)
            {
                response.StatusCode = 200;
                await WriteResponseAsync(response, "OK", "text/plain");
            }
            else
            {
                response.StatusCode = 503;
                await WriteResponseAsync(response, "UNHEALTHY", "text/plain");
            }
        }

        private static async Task WriteResponseAsync(
            HttpListenerResponse response, string content, string contentType)
        {
            response.ContentType = contentType;
            response.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate");
            response.Headers.Add("Pragma", "no-cache");
            response.Headers.Add("Expires", "0");

            var buffer = Encoding.UTF8.GetBytes(content);
            response.ContentLength64 = buffer.Length;
            await response.OutputStream.WriteAsync(buffer, 0, buffer.Length);
            response.OutputStream.Close();
        }
    }
}
