using UnityEngine;
using UnityEditor;
using System.Net;
using System.Threading;
using System.IO;
using System.Text;
using System.Collections.Generic;
using UnityEngine.SceneManagement;

[InitializeOnLoad]
public static class ThrustMCPBridge
{
    private static HttpListener listener;
    private static Thread listenerThread;

    // Buffers
    private static List<string> activityBuffer = new List<string>();
    private static List<string> consoleBuffer = new List<string>();
    private static readonly object bufferLock = new object();

    // Main Thread Dispatcher
    private static string pendingAction = null;
    private static string pendingArgument = null;
    private static string actionResult = null;
    private static volatile bool isProcessingOnMainThread = false;

    // Anti-spam tracker for property changes
    private static string lastPropertyLog = "";

    private const int PORT = 8081;

    static ThrustMCPBridge()
    {
        // 1. Hook into standard Editor Events
        EditorApplication.playModeStateChanged += OnPlayModeChanged;
        UnityEditor.SceneManagement.EditorSceneManager.sceneSaved += OnSceneSaved;
        Application.logMessageReceived += OnLogMessage;

        // 2. THE UPGRADES: Hook into Selection and Inspector edits
        Selection.selectionChanged += OnSelectionChanged;
        Undo.postprocessModifications += OnPropertyModified;

        // 3. Main thread loop & Server start
        EditorApplication.update += OnEditorUpdate;
        StartServer();
        EditorApplication.quitting += StopServer;
    }

    private static void AddActivity(string activity)
    {
        lock (bufferLock)
        {
            // Simple anti-spam: Don't log the exact same dragging action 50 times a second
            if (activity == lastPropertyLog) return;
            lastPropertyLog = activity;

            activityBuffer.Add($"[{System.DateTime.Now.ToShortTimeString()}] {activity}");
            if (activityBuffer.Count > 60) activityBuffer.RemoveAt(0);
        }
    }

    // --- NEW: EXACT CONTEXT TRACKING ---
    private static void OnSelectionChanged()
    {
        if (Selection.activeGameObject != null)
        {
            AddActivity($"Selected GameObject: '{Selection.activeGameObject.name}'");
        }
    }

    // --- UPGRADED: CATCHES CUSTOM SCRIPTS, MATERIALS, AND NOISE REDUCTION ---
    private static UndoPropertyModification[] OnPropertyModified(UndoPropertyModification[] modifications)
    {
        foreach (var mod in modifications)
        {
            if (mod.currentValue != null && mod.currentValue.target != null)
            {
                string propPath = mod.currentValue.propertyPath;
                string val = mod.currentValue.value;
                var target = mod.currentValue.target;

                // Ignore internal unity noise that the AI doesn't need to see
                if (propPath == "m_RootOrder" || propPath.Contains("m_LocalEulerAnglesHint")) continue;

                if (target is Component comp)
                {
                    AddActivity($"Set {comp.GetType().Name}.{propPath} on '{comp.gameObject.name}' to {val}");
                }
                else if (target is Material mat)
                {
                    AddActivity($"Set Material '{mat.name}' property {propPath} to {val}");
                }
                else if (target is ScriptableObject so)
                {
                    AddActivity($"Set ScriptableObject '{so.name}' property {propPath} to {val}");
                }
                else if (target is GameObject go)
                {
                    AddActivity($"Set GameObject property {propPath} on '{go.name}' to {val}");
                }
            }
        }
        return modifications;
    }

    private static void OnLogMessage(string logString, string stackTrace, LogType type)
    {
        lock (bufferLock)
        {
            if (type == LogType.Error || type == LogType.Exception || type == LogType.Warning)
            {
                consoleBuffer.Add($"[{type}] {logString}");
                if (consoleBuffer.Count > 30) consoleBuffer.RemoveAt(0);
            }
        }
    }

    private static void OnSceneSaved(Scene scene) => AddActivity($"Saved scene: {scene.name}");
    private static void OnPlayModeChanged(PlayModeStateChange state) => AddActivity($"Play mode state: {state}");

    // --- HTTP SERVER LOOP (Background Thread) ---
    private static void StartServer()
    {
        if (listener != null && listener.IsListening) return;
        listener = new HttpListener();
        listener.Prefixes.Add($"http://localhost:{PORT}/");
        listener.Start();

        listenerThread = new Thread(ListenForRequests) { IsBackground = true };
        listenerThread.Start();
        Debug.Log($"[Thrust MCP] Deep Unity Bridge active on port {PORT}...");
    }

    private static void ListenForRequests()
    {
        while (listener != null && listener.IsListening)
        {
            try { ProcessRequest(listener.GetContext()); }
            catch (HttpListenerException) { /* Ignored on shutdown */ }
        }
    }

    private static void ProcessRequest(HttpListenerContext context)
    {
        var request = context.Request;
        var response = context.Response;

        response.AddHeader("Access-Control-Allow-Origin", "*");
        response.AddHeader("Access-Control-Allow-Headers", "Content-Type");

        if (request.HttpMethod == "OPTIONS") { SendResponse(response, ""); return; }

        string requestBody;
        using (var reader = new StreamReader(request.InputStream, request.ContentEncoding))
        {
            requestBody = reader.ReadToEnd();
        }

        string resultText = "Unknown command";

        if (requestBody.Contains("\"name\":\"get_initial_state\"") || requestBody.Contains("\"name\": \"get_initial_state\""))
        {
            // NEW: Give Thrust a summary of the environment on boot
            string activeScene = SceneManager.GetActiveScene().name;
            string selected = Selection.activeGameObject != null ? Selection.activeGameObject.name : "None";
            
            resultText = $"Unity Environment Boot State:\\n" +
                         $"- Active Scene: {activeScene}\\n" +
                         $"- Currently Selected Object: {selected}\\n" +
                         $"- Editor Mode: {(EditorApplication.isPlaying ? "Play Mode" : "Edit Mode")}";
        }
        else if (requestBody.Contains("\"name\":\"get_recent_activity\"") || requestBody.Contains("\"name\": \"get_recent_activity\""))
        {
            lock (bufferLock)
            {
                resultText = activityBuffer.Count == 0 ? "No new activity" : string.Join("\\n", activityBuffer);
                activityBuffer.Clear();
            }
        }
        else if (requestBody.Contains("\"name\":\"get_console_logs\"") || requestBody.Contains("\"name\": \"get_console_logs\""))
        {
            lock (bufferLock)
            {
                resultText = consoleBuffer.Count == 0 ? "No recent errors/warnings." : string.Join("\\n", consoleBuffer).Replace("\"", "'");
                consoleBuffer.Clear();
            }
        }
        else if (requestBody.Contains("\"name\":\"get_hierarchy\"") || requestBody.Contains("\"name\": \"get_hierarchy\""))
        {
            resultText = DispatchToMainThread("get_hierarchy", "");
        }
        else if (requestBody.Contains("\"name\":\"get_properties\"") || requestBody.Contains("\"name\": \"get_properties\""))
        {
            string target = ExtractJsonValue(requestBody, "target");
            resultText = DispatchToMainThread("get_properties", target);
        }

        string responseJson = $@"{{
            ""jsonrpc"": ""2.0"",
            ""result"": {{ ""content"":[{{ ""type"": ""text"", ""text"": ""{resultText}"" }}] }}
        }}";

        SendResponse(response, responseJson);
    }

    // --- MAIN THREAD DISPATCHER ---
    private static string DispatchToMainThread(string action, string arg)
    {
        pendingAction = action;
        pendingArgument = arg;
        actionResult = null;
        isProcessingOnMainThread = true;

        while (isProcessingOnMainThread) { Thread.Sleep(10); }
        return actionResult;
    }

    private static void OnEditorUpdate()
    {
        if (!isProcessingOnMainThread) return;

        try
        {
            if (pendingAction == "get_hierarchy")
            {
                var rootObjects = SceneManager.GetActiveScene().GetRootGameObjects();
                string hierarchy = "Active Scene Hierarchy:\\n";
                foreach (var go in rootObjects) hierarchy += $"- {go.name}\\n";
                actionResult = hierarchy;
            }
            else if (pendingAction == "get_properties")
            {
                if (string.IsNullOrEmpty(pendingArgument)) {
                    actionResult = "Error: No target specified.";
                } else {
                    GameObject go = GameObject.Find(pendingArgument);
                    if (go == null) {
                        actionResult = $"GameObject '{pendingArgument}' not found in active scene.";
                    } else {
                        actionResult = $"Properties for '{go.name}':\\nPosition: {go.transform.position}\\nRotation: {go.transform.eulerAngles}\\nComponents:\\n";
                        foreach (var comp in go.GetComponents<Component>())
                        {
                            if(comp != null) actionResult += $"- {comp.GetType().Name}\\n";
                        }
                    }
                }
            }
        }
        catch (System.Exception e) { actionResult = $"Error reading Unity state: {e.Message}"; }

        isProcessingOnMainThread = false;
    }

    private static string ExtractJsonValue(string json, string key)
    {
        string search = $"\"{key}\":";
        int index = json.IndexOf(search);
        if (index == -1) search = $"\"{key}\" :"; index = json.IndexOf(search);
        if (index == -1) return "";

        int start = json.IndexOf("\"", index + search.Length) + 1;
        int end = json.IndexOf("\"", start);
        return json.Substring(start, end - start);
    }

    private static void SendResponse(HttpListenerResponse response, string json)
    {
        byte[] buffer = Encoding.UTF8.GetBytes(json);
        response.ContentType = "application/json";
        response.ContentLength64 = buffer.Length;
        response.OutputStream.Write(buffer, 0, buffer.Length);
        response.OutputStream.Close();
    }

    private static void StopServer()
    {
        if (listener != null) { listener.Stop(); listener.Close(); listener = null; }
        if (listenerThread != null) { listenerThread.Abort(); listenerThread = null; }
    }
}
