using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;

namespace JebAI
{
    public sealed class ModelCallResult
    {
        public bool Success;
        public string Reply;
        public string Error;
        public long StatusCode;
    }

    /// <summary>
    /// Central model control plane for all Kerbal interactions.
    /// Uses UnityWebRequest against an OpenAI-compatible local server so the mod
    /// can run inside KSP without System.Net.Http.
    /// </summary>
    public sealed class JebAIMcpLayer : MonoBehaviour
    {
        public static JebAIMcpLayer Instance { get; private set; }

        private int _activeRequests = 0;
        private string _lastStatus = "Idle";
        private string _lastError = "";

        public string DescribeStatus()
        {
            if (_activeRequests > 0)
                return $"{_lastStatus} ({_activeRequests} active)";

            if (!string.IsNullOrEmpty(_lastError))
                return $"Error: {_lastError}";

            return _lastStatus;
        }

        void Awake()
        {
            if (Instance != null && Instance != this) { Destroy(gameObject); return; }
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }

        public void RequestCompletion(
            string systemPrompt,
            List<ChatMessage> history,
            string userMessage,
            int maxTokens,
            string debugLabel,
            Action<ModelCallResult> onComplete)
        {
            if (!isActiveAndEnabled)
            {
                onComplete?.Invoke(new ModelCallResult
                {
                    Success = false,
                    Error = "MCP layer is unavailable.",
                });
                return;
            }

            StartCoroutine(RequestCompletionRoutine(
                systemPrompt,
                history,
                userMessage,
                maxTokens,
                debugLabel,
                onComplete));
        }

        public void ProbeServer()
        {
            StartCoroutine(ProbeServerRoutine());
        }

        private IEnumerator RequestCompletionRoutine(
            string systemPrompt,
            List<ChatMessage> history,
            string userMessage,
            int maxTokens,
            string debugLabel,
            Action<ModelCallResult> onComplete)
        {
            string endpoint = JebAISettings.Instance.GetChatCompletionsUrl();
            string body = OpenAICompatClient.BuildRequestBody(systemPrompt, history, userMessage, maxTokens);
            byte[] payload = Encoding.UTF8.GetBytes(body);
            int messageCount = OpenAICompatClient.BuildMessageCount(systemPrompt, history, userMessage);

            _activeRequests++;
            _lastStatus = $"Requesting {debugLabel}";
            _lastError = "";

            Debug.Log($"[JebAI MCP] -> {debugLabel} @ {endpoint} (messages={messageCount}, bytes={payload.Length})");

            var request = new UnityWebRequest(endpoint, UnityWebRequest.kHttpVerbPOST)
            {
                uploadHandler = new UploadHandlerRaw(payload),
                downloadHandler = new DownloadHandlerBuffer(),
                timeout = Mathf.Max(1, JebAISettings.Instance.RequestTimeoutSeconds),
            };
            request.SetRequestHeader("Content-Type", "application/json");
            request.SetRequestHeader("Accept", "application/json");

            yield return request.SendWebRequest();

            string raw = request.downloadHandler != null ? request.downloadHandler.text : "";
            bool failed = request.isNetworkError || request.isHttpError;
            var result = new ModelCallResult
            {
                StatusCode = request.responseCode,
            };

            if (failed)
            {
                string detail = OpenAICompatClient.TryExtractError(raw);
                result.Success = false;
                result.Error = $"HTTP {request.responseCode}: {detail}";
                _lastError = result.Error;
                _lastStatus = $"Request failed for {debugLabel}";
                Debug.LogError($"[JebAI MCP] {result.Error}");
            }
            else if (!OpenAICompatClient.TryParseResponse(raw, out string reply, out string error))
            {
                bool retried = false;
                bool looksReasoningOnly = OpenAICompatClient.LooksReasoningOnlyResponse(raw);
                bool looksEmptyChoices = !string.IsNullOrEmpty(error) &&
                    error.IndexOf("empty choices", StringComparison.OrdinalIgnoreCase) >= 0;

                if (JebAISettings.Instance.RetryOnReasoningOnly &&
                    (looksReasoningOnly || looksEmptyChoices))
                {
                    retried = true;
                    int retryMaxTokens = Mathf.Max(
                        maxTokens * 2,
                        maxTokens + Mathf.Max(24, JebAISettings.Instance.ReasoningRetryExtraTokens));
                    if (JebAISettings.Instance.DisableModelThinking)
                        retryMaxTokens = Mathf.Max(retryMaxTokens, 320);

                    string retrySystem = systemPrompt +
                        "\n\nFINAL OUTPUT MODE: return only final visible reply text. No reasoning trace, no analysis preamble.";
                    string retryBody = OpenAICompatClient.BuildRequestBody(
                        retrySystem,
                        history,
                        userMessage,
                        retryMaxTokens);
                    byte[] retryPayload = Encoding.UTF8.GetBytes(retryBody);

                    Debug.LogWarning(
                        $"[JebAI MCP] {debugLabel} returned reasoning-only content. Retrying with max_tokens={retryMaxTokens}.");

                    using (var retryRequest = new UnityWebRequest(endpoint, UnityWebRequest.kHttpVerbPOST))
                    {
                        retryRequest.uploadHandler = new UploadHandlerRaw(retryPayload);
                        retryRequest.downloadHandler = new DownloadHandlerBuffer();
                        retryRequest.timeout = Mathf.Max(1, JebAISettings.Instance.RequestTimeoutSeconds);
                        retryRequest.SetRequestHeader("Content-Type", "application/json");
                        retryRequest.SetRequestHeader("Accept", "application/json");

                        yield return retryRequest.SendWebRequest();

                        string retryRaw = retryRequest.downloadHandler != null ? retryRequest.downloadHandler.text : "";
                        bool retryFailed = retryRequest.isNetworkError || retryRequest.isHttpError;
                        string retryParseError = null;

                        if (!retryFailed && OpenAICompatClient.TryParseResponse(retryRaw, out string retryReply, out retryParseError))
                        {
                            result.Success = true;
                            result.Reply = retryReply;
                            result.StatusCode = retryRequest.responseCode;
                            _lastStatus = $"Last reply ok (retry): {debugLabel}";
                            _lastError = "";
                            Debug.Log($"[JebAI MCP] <- {debugLabel} (retry): {retryReply}");
                        }
                        else
                        {
                            string retryDetail = retryFailed
                                ? $"HTTP {retryRequest.responseCode}: {OpenAICompatClient.TryExtractError(retryRaw)}"
                                : $"Retry parse failed: {retryParseError}";
                            Debug.LogWarning($"[JebAI MCP] Retry failed for {debugLabel}: {retryDetail}");
                        }
                    }
                }

                if (!result.Success)
                {
                    result.Success = false;
                    result.Error = error;
                    _lastError = error;
                    _lastStatus = retried
                        ? $"Parse failed after retry for {debugLabel}"
                        : $"Parse failed for {debugLabel}";
                    Debug.LogError($"[JebAI MCP] {error}");
                    if (!string.IsNullOrWhiteSpace(raw))
                    {
                        string preview = raw.Length > 600 ? raw.Substring(0, 600) + "..." : raw;
                        Debug.LogWarning($"[JebAI MCP] Raw response preview for {debugLabel}: {preview}");
                    }
                }
            }
            else
            {
                result.Success = true;
                result.Reply = reply;
                _lastStatus = $"Last reply ok: {debugLabel}";
                _lastError = "";
                Debug.Log($"[JebAI MCP] <- {debugLabel}: {reply}");
            }

            _activeRequests = Mathf.Max(0, _activeRequests - 1);
            request.Dispose();
            onComplete?.Invoke(result);
        }

        private IEnumerator ProbeServerRoutine()
        {
            string endpoint = JebAISettings.Instance.GetModelsUrl();
            _lastStatus = "Pinging server endpoint";
            _lastError = "";

            Debug.Log($"[JebAI MCP] -> Probe @ {endpoint}");
            using (UnityWebRequest request = UnityWebRequest.Get(endpoint))
            {
                request.timeout = Mathf.Max(1, JebAISettings.Instance.RequestTimeoutSeconds);
                yield return request.SendWebRequest();

                bool failed = request.isNetworkError || request.isHttpError;
                if (failed)
                {
                    string detail = OpenAICompatClient.TryExtractError(request.downloadHandler?.text);
                    _lastError = $"Probe failed: HTTP {request.responseCode}: {detail}";
                    _lastStatus = "Probe failed";
                    ScreenMessages.PostScreenMessage(
                        $"[JebAI] MCP probe failed: {detail}",
                        4f,
                        ScreenMessageStyle.UPPER_CENTER);
                }
                else
                {
                    _lastStatus = "Probe succeeded";
                    _lastError = "";
                    ScreenMessages.PostScreenMessage(
                        $"[JebAI] MCP probe reached {JebAISettings.Instance.GetServerDisplayName()}.",
                        3f,
                        ScreenMessageStyle.UPPER_CENTER);
                }
            }
        }
    }
}
