using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using PolyTrader.Modules.Supervisor.Agent;
using PolyTraderSharp.Services;

namespace PolyTrader.Modules.Supervisor.Mcp
{
    /// <summary>
    /// MCP-Light-Host (S-4): lokaler HTTP-Endpoint (Streamable-HTTP-Transport, nur POST-JSON), der die
    /// read-only Tool-Registry per Model Context Protocol exponiert. Externe Clients wie Claude Code
    /// verbinden sich mit: <c>claude mcp add --transport http polytrader http://127.0.0.1:PORT/mcp</c>.
    ///
    /// SICHERHEIT: bewusst OPT-IN (startet nur, wenn die Umgebungsvariable POLYTRADER_MCP_PORT gesetzt
    /// ist) und bindet ausschließlich an 127.0.0.1 (kein Netzwerkzugriff). Die Tools sind read-only —
    /// es existiert kein Mechanismus zum Handeln/Schreiben. Kein Modell-Zugang: MCP ist nur die
    /// Daten-Tür; Modelle laufen weiterhin über OpenRouter (In-App-Agent) bzw. den externen Client.
    /// </summary>
    public sealed class McpLightServer : BackgroundService
    {
        private readonly SupervisorToolRegistry _registry;
        private readonly TerminalLogger _logger;

        public McpLightServer(SupervisorToolRegistry registry, TerminalLogger logger)
        {
            _registry = registry;
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            string? portRaw = Environment.GetEnvironmentVariable("POLYTRADER_MCP_PORT");
            if (string.IsNullOrWhiteSpace(portRaw))
            {
                _logger.Info("MCP-Light: deaktiviert (POLYTRADER_MCP_PORT nicht gesetzt).");
                return;
            }
            if (!int.TryParse(portRaw, out int port) || port is < 1024 or > 65535)
            {
                _logger.Warning($"MCP-Light: ungültiger Port '{portRaw}' – Server startet nicht.");
                return;
            }

            using var listener = new HttpListener();
            listener.Prefixes.Add($"http://127.0.0.1:{port}/mcp/");
            try { listener.Start(); }
            catch (Exception ex)
            {
                _logger.Error($"MCP-Light: Start auf Port {port} fehlgeschlagen: {ex.Message}");
                return;
            }

            _logger.Info($"🔌 MCP-Light aktiv: http://127.0.0.1:{port}/mcp (read-only, {_registry.Tools.Count} Tools). " +
                         $"Claude Code: claude mcp add --transport http polytrader http://127.0.0.1:{port}/mcp");

            using var reg = stoppingToken.Register(() => { try { listener.Stop(); } catch { } });
            while (!stoppingToken.IsCancellationRequested)
            {
                HttpListenerContext ctx;
                try { ctx = await listener.GetContextAsync(); }
                catch when (stoppingToken.IsCancellationRequested) { break; }
                catch (Exception ex) { _logger.Warning($"MCP-Light: Listener-Fehler: {ex.Message}"); continue; }

                _ = Task.Run(() => HandleRequestAsync(ctx), stoppingToken);
            }
        }

        private async Task HandleRequestAsync(HttpListenerContext ctx)
        {
            try
            {
                if (ctx.Request.HttpMethod != "POST")
                {
                    ctx.Response.StatusCode = 405;   // GET/SSE-Stream bieten wir bewusst nicht an
                    ctx.Response.Close();
                    return;
                }

                string body;
                using (var reader = new StreamReader(ctx.Request.InputStream, ctx.Request.ContentEncoding))
                    body = await reader.ReadToEndAsync();

                string? response = McpJsonRpc.Handle(body, _registry);
                if (response == null)
                {
                    ctx.Response.StatusCode = 202;   // Notification: angenommen, keine Antwort
                    ctx.Response.Close();
                    return;
                }

                byte[] bytes = Encoding.UTF8.GetBytes(response);
                ctx.Response.StatusCode = 200;
                ctx.Response.ContentType = "application/json";
                ctx.Response.ContentLength64 = bytes.Length;
                await ctx.Response.OutputStream.WriteAsync(bytes);
                ctx.Response.Close();
            }
            catch (Exception ex)
            {
                _logger.Warning($"MCP-Light: Request-Fehler: {ex.Message}");
                try { ctx.Response.StatusCode = 500; ctx.Response.Close(); } catch { }
            }
        }
    }
}
