using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;
using UnityEditor;
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.Requests;
using UnityEngine;
using Newtonsoft.Json;
using SynapticAIPro;

namespace SynapticPro
{
    /// <summary>
    /// MCP Server Setup and Local CLI Management Window
    /// One-touch setup for MCP server and configuration of various AI tools
    /// </summary>
    public class NexusMCPSetupWindow : EditorWindow
    {
        [MenuItem("Tools/Synaptic Pro/Synaptic Setup", false, 0)]
        public static void ShowWindow()
        {
            var window = GetWindow<NexusMCPSetupWindow>("Synaptic Pro Setup");
            // 小さい画面でも使えるようminSizeを緩和（旧: 800x800で固定気味）
            window.minSize = new Vector2(480, 480);
            window.Show();
        }

        private NexusMCPSetupManager mcpSetupManager;
        private NexusMCPSetupManager.SetupStatus mcpStatus;
        private Vector2 scrollPosition;
        private bool mcpServerRunning = false;

        // Tabs
        private int selectedTab = 0;
        private string[] tabNames = new string[] { "AI Connection", "HTTP Server", "Help" };

        // MCP Settings
        private int mcpPort = 8090;
        private int wsPort = 8090;

        // HTTP Server Settings
        private int httpPort = 8086;
        private bool httpServerRunning = false;

        // Use project-specific keys for HTTP settings
        private static string ProjectKey => Application.dataPath.GetHashCode().ToString("X8");
        private static string PREF_HTTP_PORT => $"SynapticPro_HTTP_Port_{ProjectKey}";
        private static string PREF_HTTP_AUTO_START => $"SynapticPro_HTTP_AutoStart_{ProjectKey}";

        // External HTTP Server Process
        private static System.Diagnostics.Process externalHttpProcess = null;
        private static bool externalHttpRunning = false;
        private static bool externalAutoStartAttempted = false;

        // Port-probe throttle. Probing runs on a background thread; UI reads the cached
        // `externalHttpRunning` so OnGUI never blocks on a TCP connect.
        private static double lastPortCheckTime = -100;
        private static bool portCheckInFlight = false;
        private const double PORT_CHECK_INTERVAL_SEC = 2.0;
        private const int PORT_CHECK_TIMEOUT_MS = 500;

        // Auto-Update
        private static bool updateCheckDone = false;
        private static bool updateAvailable = false;
        private static string latestVersion = "";
        private static string updateUrl = "";
        private static string updateMethod = "browser"; // "browser" or "auto"
        private static bool isDownloadingUpdate = false;

        // Distribution type: "assetstore" or "booth"
        // Asset Store版はfalse（ブラウザでAsset Storeに飛ばす）、BOOTH/サイト版はtrue（自動ダウンロード）
        private static readonly bool ENABLE_SELF_UPDATE = false; // Asset Store版リリース時にfalseに変更

        public static bool HttpAutoStartEnabled
        {
            get => EditorPrefs.GetBool(PREF_HTTP_AUTO_START, false);
            set => EditorPrefs.SetBool(PREF_HTTP_AUTO_START, value);
        }

        // Animation
        private bool isConnecting = false;
        private float animationTime = 0f;
        private const float CONNECTION_TIMEOUT = 60f; // 60 second timeout

        // Setup state management
        private bool mcpConfigured = false;

        // AI Client selection (v1.1.3)
        private enum AIClientType
        {
            ClaudeDesktopOrCursor,      // Full mode (index.js) - 246 tools
            CursorOrLMStudioEssential,  // Essential mode (index-essential.js) - 80 tools
            GitHubCopilot,              // Dynamic mode (hub-server.js) - 8→dynamic tools
            TokenSuperSaveMode          // Experimental: 3 meta-tools only (index-supersave.js)
        }
        private AIClientType selectedAIClient = AIClientType.TokenSuperSaveMode;

        private string[] connectingMessages = new string[] 
        {
            "Preparing AI Connection",
            "Starting MCP Server",
            "Establishing connection with desktop AI apps",
            "Auto-generating configuration files",
            "AI connection almost ready"
        };
        
        private GUIStyle headerStyle;
        private GUIStyle setupButtonStyle;
        private GUIStyle statusStyle;
        
        private void OnEnable()
        {
            mcpSetupManager = NexusMCPSetupManager.Instance;

            // Load HTTP Server settings first (no blocking)
            httpPort = EditorPrefs.GetInt(PREF_HTTP_PORT, 8086);

            // Check if server is still running
            CheckExternalHttpServerStatus();

            // Try auto-start
            TryHttpAutoStart();

            // Check for updates (background, 1日1回)
            CheckForUpdates();

            // Refresh MCP status in background thread (completely non-blocking)
            System.Threading.ThreadPool.QueueUserWorkItem(async _ =>
            {
                try
                {
                    mcpStatus = await mcpSetupManager.CheckSetupStatus();
                    // UI更新はメインスレッドで
                    EditorApplication.delayCall += () => { if (this) Repaint(); };
                }
                catch { }
            });
        }

        private void OnDisable()
        {
            // Save HTTP Server settings
            EditorPrefs.SetInt(PREF_HTTP_PORT, httpPort);
            // サーバーはここで止めない（ドメインリロードで毎回止まるため）
            // Unity終了時はRegisterQuitHandlerで停止する
        }

        // Unity終了時にNode.jsプロセスを確実に停止
        [UnityEditor.InitializeOnLoadMethod]
        private static void RegisterQuitHandler()
        {
            EditorApplication.quitting += () =>
            {
                var port = EditorPrefs.GetInt(PREF_HTTP_PORT, 8086);
                try
                {
                    // ポートを使っているプロセスを強制終了
                    if (Application.platform == RuntimePlatform.WindowsEditor)
                    {
                        var p = new System.Diagnostics.Process
                        {
                            StartInfo = new System.Diagnostics.ProcessStartInfo
                            {
                                FileName = "cmd.exe",
                                Arguments = $"/c \"for /f \"tokens=5\" %a in ('netstat -aon ^| findstr :{port} ^| findstr LISTENING') do taskkill /PID %a /F\"",
                                UseShellExecute = false,
                                CreateNoWindow = true
                            }
                        };
                        p.Start();
                        p.WaitForExit(3000);
                    }
                    else
                    {
                        var p = new System.Diagnostics.Process
                        {
                            StartInfo = new System.Diagnostics.ProcessStartInfo
                            {
                                FileName = "/bin/bash",
                                Arguments = $"-c \"lsof -ti:{port} | xargs kill -9 2>/dev/null\"",
                                UseShellExecute = false,
                                CreateNoWindow = true
                            }
                        };
                        p.Start();
                        p.WaitForExit(3000);
                    }
                    SynLog.Info($"[Synaptic] Killed HTTP server process on port {port} (Unity quitting)");
                }
                catch { }
            };
        }

        // Unity起動時にアップデートチェック（Setup Windowを開かなくても通知）
        /// <summary>
        /// After domain reload, recover the previously spawned detached
        /// node.exe by re-attaching to its PID stored in SessionState.
        /// Only the WebSocket needs reconnecting — the HTTP process itself
        /// was started detached and survives across reloads.
        /// </summary>
        [InitializeOnLoadMethod]
        private static void RestoreDetachedHttpServerOnReload()
        {
            EditorApplication.delayCall += () =>
            {
                // Windows detached path: recover by PID stored in SessionState.
                if (Application.platform == RuntimePlatform.WindowsEditor &&
                    SynapticDetachedProcess.IsStoredProcessAlive(out int pid, out int wPort))
                {
                    externalHttpRunning = true;
                    EditorPrefs.SetInt(PREF_HTTP_PORT, wPort);
                    SynLog.Info($"[Synaptic] Recovered detached HTTP server PID={pid} on port {wPort}. Reconnecting WebSocket.");
                    _ = ReconnectWebSocketOnlyAsync(wPort);
                    return;
                }

                // Generic path (Mac/Linux, or Windows fallback): probe last-used
                // port; if a server is listening, just reconnect WS.
                int port = EditorPrefs.GetInt(PREF_HTTP_PORT, 8086);
                if (IsPortListeningStatic(port))
                {
                    externalHttpRunning = true;
                    SynLog.Info($"[Synaptic] HTTP server alive on port {port} after reload. Reconnecting WebSocket.");
                    _ = ReconnectWebSocketOnlyAsync(port);
                    return;
                }

                // Server is dead. If the user opted into HTTP auto-start,
                // bring the Setup window up so its OnEnable → TryHttpAutoStart
                // path can re-spawn the node process. Without this nudge the
                // NexusHTTPWebSocketClient retry loop just hammers a closed
                // port forever (the client cannot start its own server).
                if (Application.platform == RuntimePlatform.WindowsEditor)
                {
                    // Stored PID is stale and port dead — clear for fresh spawn.
                    SynapticDetachedProcess.ClearStoredPid();
                }
                if (HttpAutoStartEnabled)
                {
                    SynLog.Info("[Synaptic] HTTP server not running after reload; opening Setup window to auto-restart.");
                    // GetWindow opens existing or creates new; OnEnable fires
                    // TryHttpAutoStart which spawns the node process.
                    EditorWindow.GetWindow<NexusMCPSetupWindow>("Synaptic Setup", true);
                }
            };
        }

        /// <summary>
        /// Static port-alive probe usable from [InitializeOnLoadMethod].
        /// Lightweight TCP connect with short timeout.
        /// </summary>
        private static bool IsPortListeningStatic(int port)
        {
            try
            {
                using (var tcp = new System.Net.Sockets.TcpClient())
                {
                    var ar = tcp.BeginConnect("127.0.0.1", port, null, null);
                    bool ok = ar.AsyncWaitHandle.WaitOne(500);
                    if (!ok) return false;
                    try { tcp.EndConnect(ar); return true; } catch { return false; }
                }
            }
            catch { return false; }
        }

        /// <summary>
        /// Reconnect WebSocket to an already-running HTTP server after domain
        /// reload. Does not start the server or open any UI.
        /// </summary>
        private static async System.Threading.Tasks.Task ReconnectWebSocketOnlyAsync(int port)
        {
            // Light delay so the editor finishes loading other systems first.
            await System.Threading.Tasks.Task.Delay(500);
            for (int i = 0; i < 3; i++)
            {
                bool ok = await NexusHTTPWebSocketClient.Instance.Connect(port);
                if (ok)
                {
                    SynLog.Info($"[Synaptic] WebSocket re-attached to port {port} after reload.");
                    return;
                }
                await System.Threading.Tasks.Task.Delay(1500);
            }
            SynLog.Warn($"[Synaptic] Could not reconnect WebSocket to port {port}. Use Setup window to reconnect manually.");
        }

        [InitializeOnLoadMethod]
        private static void CheckForUpdatesOnStartup()
        {
            // エディタ起動直後は少し待つ
            EditorApplication.delayCall += () =>
            {
                // 1日1回チェック
                var lastCheck = EditorPrefs.GetString("SynapticPro_LastStartupUpdateCheck", "");
                var today = DateTime.Now.ToString("yyyy-MM-dd");
                if (lastCheck == today) return;
                EditorPrefs.SetString("SynapticPro_LastStartupUpdateCheck", today);

                var currentVersion = NexusVersion.Current;
                var dist = ENABLE_SELF_UPDATE ? "booth" : "assetstore";

                System.Threading.ThreadPool.QueueUserWorkItem(_ =>
                {
                    try
                    {
                        using (var client = new System.Net.WebClient())
                        {
                            client.Headers.Add("User-Agent", "SynapticAIPro-Unity");
                            var url = $"https://kawaii-agent-backend.vercel.app/api/synaptic/unity-version?v={currentVersion}&dist={dist}";
                            var json = client.DownloadString(url);

                            if (json.Contains("\"updateAvailable\":true") || json.Contains("\"updateAvailable\": true"))
                            {
                                var vMatch = System.Text.RegularExpressions.Regex.Match(json, "\"latestVersion\"\\s*:\\s*\"([^\"]+)\"");
                                if (vMatch.Success)
                                {
                                    var newVersion = vMatch.Groups[1].Value;
                                    EditorApplication.delayCall += () =>
                                    {
                                        var result = EditorUtility.DisplayDialog(
                                            "Synaptic AI Pro - Update Available",
                                            $"A new version is available!\n\n" +
                                            $"Current: v{currentVersion}\n" +
                                            $"Latest: v{newVersion}\n\n" +
                                            (ENABLE_SELF_UPDATE
                                                ? "Would you like to update now?"
                                                : "Would you like to open the Asset Store?"),
                                            ENABLE_SELF_UPDATE ? "Update Now" : "Open Store",
                                            "Later"
                                        );

                                        if (result)
                                        {
                                            if (ENABLE_SELF_UPDATE)
                                            {
                                                // Setup Windowを開いてアップデート実行
                                                var window = GetWindow<NexusMCPSetupWindow>("Synaptic Pro Setup");
                                                window.Show();
                                                updateAvailable = true;
                                                latestVersion = newVersion;
                                                var urlMatch = System.Text.RegularExpressions.Regex.Match(json, "\"updateUrl\"\\s*:\\s*\"([^\"]+)\"");
                                                updateUrl = urlMatch.Success ? urlMatch.Groups[1].Value : "";
                                                updateMethod = "auto";
                                                window.StartAutoUpdate();
                                            }
                                            else
                                            {
                                                Application.OpenURL("https://assetstore.unity.com/packages/tools/generative-ai/synaptic-ai-pro-natural-language-control-for-unity-336030");
                                            }
                                        }
                                    };
                                }
                            }
                        }
                    }
                    catch { /* フェイルサイレント */ }
                });
            };
        }

        private void TryHttpAutoStart()
        {
            if (externalAutoStartAttempted) return;
            externalAutoStartAttempted = true;

            if (HttpAutoStartEnabled && !externalHttpRunning)
            {
                // まず既存サーバーが生きてるかチェック
                if (IsPortListening(httpPort))
                {
                    // 既にサーバーが動いてる（前回のプロセスが残ってる）→ 再接続のみ
                    externalHttpRunning = true;
                    SynLog.Info("[Synaptic] Auto-start: Existing server detected, reconnecting...");
                    _ = ConnectToHttpServerAsync(httpPort);
                }
                else
                {
                    // サーバーがない → 新規起動
                    SynLog.Info("[Synaptic] Auto-starting HTTP Server...");
                    StartExternalHttpServer();
                }
            }
        }
        
        private void InitializeStyles()
        {
            headerStyle = new GUIStyle(EditorStyles.largeLabel)
            {
                fontSize = 24,
                fontStyle = FontStyle.Bold,
                alignment = TextAnchor.MiddleCenter,
                normal = { textColor = new Color(0.2f, 0.6f, 1f) }
            };
            
            setupButtonStyle = new GUIStyle(GUI.skin.button)
            {
                fontSize = 18,
                fontStyle = FontStyle.Bold,
                padding = new RectOffset(20, 20, 10, 10),
                normal = { background = CreateColorTexture(new Color(0.2f, 0.6f, 1f)) },
                hover = { background = CreateColorTexture(new Color(0.3f, 0.7f, 1f)) },
                active = { background = CreateColorTexture(new Color(0.1f, 0.5f, 0.9f)) }
            };
            
            statusStyle = new GUIStyle(EditorStyles.helpBox)
            {
                fontSize = 14,
                padding = new RectOffset(10, 10, 10, 10),
                wordWrap = true
            };
        }
        
        private Texture2D CreateColorTexture(Color color)
        {
            var texture = new Texture2D(1, 1);
            texture.SetPixel(0, 0, color);
            texture.Apply();
            return texture;
        }
        
        private void OnGUI()
        {
            if (headerStyle == null)
                InitializeStyles();
            
            DrawHeader();
            DrawUpdateBanner();

            // Tab rendering
            selectedTab = GUILayout.Toolbar(selectedTab, tabNames, GUILayout.Height(30));

            // Animation update (non-blocking)
            if (isConnecting)
            {
                animationTime += Time.deltaTime;
                // Use delayed call instead of direct Repaint to avoid "Hold on" blocking
                EditorApplication.delayCall += () => { if (this) Repaint(); };
            }
            EditorGUILayout.Space(10);
            
            switch (selectedTab)
            {
                case 0:
                    DrawAIConnectionTab();
                    break;
                case 1:
                    DrawHTTPServerTab();
                    break;
                case 2:
                    DrawHelpTab();
                    break;
            }
        }
        
        /// <summary>
        /// Compact toolbar with live MCP connection controls. Visible only in the
        /// AI Connection tab — the HTTP Server tab uses its own port lifecycle
        /// and these controls don't apply there.
        /// </summary>
        private void DrawConnectionControlsBar()
        {
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);

            EditorGUILayout.BeginHorizontal();

            // Status indicator: a small color-coded square + plain text label.
            // Using a textured box (drawn via a colored rect) instead of an
            // emoji bullet so the visual works under any system font.
            bool connected = NexusEditorMCPService.IsConnected;
            var statusColor = connected ? new Color(0.2f, 0.8f, 0.2f) : new Color(0.7f, 0.45f, 0.2f);
            var dotRect = GUILayoutUtility.GetRect(10, 10, GUILayout.Width(10), GUILayout.Height(10));
            // Vertical-center the dot relative to surrounding label baseline.
            dotRect.y += 5;
            EditorGUI.DrawRect(dotRect, statusColor);
            GUILayout.Space(4);
            GUILayout.Label(connected ? "MCP Connected" : "MCP Disconnected", EditorStyles.boldLabel, GUILayout.Width(160));

            GUILayout.FlexibleSpace();

            // Built-in Editor icons — no emoji, render consistently across OS.
            //   "Refresh"  : circular arrow (used by Asset refresh, Console clear)
            //   "linkicon" : chain link (Editor's link icon, varies by version)
            var reconnectIcon = EditorGUIUtility.IconContent("Refresh");
            var reconnectContent = new GUIContent(" AI Reconnect", reconnectIcon.image, "Reconnect to MCP server");
            if (GUILayout.Button(reconnectContent, GUILayout.Width(130), GUILayout.Height(22)))
            {
                NexusEditorMCPService.QuickReconnect();
            }

            EditorGUILayout.Space(4);

            // Auto Reconnect toggle — direct binding to the EditorPrefs-backed property.
            bool prevAuto = NexusEditorMCPService.AutoReconnectEnabled;
            bool nextAuto = GUILayout.Toggle(prevAuto, new GUIContent(" Auto Reconnect", "Automatically reconnect when the connection drops"), GUILayout.Width(130));
            if (nextAuto != prevAuto)
            {
                NexusEditorMCPService.AutoReconnectEnabled = nextAuto;
            }

            EditorGUILayout.Space(4);

            // No Unity built-in icon for Discord — use a small link/external
            // icon ("BuildSettings.Web.Small" is the closest globe-like icon
            // across Unity 2022 / 6.x). Fall back to plain text on failure.
            GUIContent discordContent;
            try
            {
                var icon = EditorGUIUtility.IconContent("BuildSettings.Web.Small");
                discordContent = new GUIContent(" Discord", icon != null ? icon.image : null, "Join the Synaptic Discord community");
            }
            catch
            {
                discordContent = new GUIContent("Discord", "Join the Synaptic Discord community");
            }
            if (GUILayout.Button(discordContent, GUILayout.Width(90), GUILayout.Height(22)))
            {
                NexusEditorMCPService.OpenDiscord();
            }

            EditorGUILayout.EndHorizontal();

            EditorGUILayout.EndVertical();
            EditorGUILayout.Space(8);
        }

        private void DrawHeader()
        {
            EditorGUILayout.Space(10);
            GUILayout.Label("Synaptic Pro Setup", headerStyle, GUILayout.Height(40));
            EditorGUILayout.Space(10);
            
            // Concise status display (常にBegin/Endを呼ぶ - GUILayout不一致防止)
            EditorGUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();

            var statusText = "Loading...";
            var statusColor = Color.gray;

            if (mcpStatus != null)
            {
                if (mcpServerRunning)
                {
                    statusText = "MCP Server Running";
                    statusColor = Color.green;
                }
                else if (mcpStatus.isMCPInstalled)
                {
                    statusText = "AI Connection Ready";
                    statusColor = new Color(0.2f, 0.8f, 0.2f);
                }
                else
                {
                    statusText = "Initial Setup";
                    statusColor = new Color(0.5f, 0.5f, 0.5f);
                }
            }

            var oldColor = GUI.contentColor;
            GUI.contentColor = statusColor;
            GUILayout.Label(statusText, EditorStyles.boldLabel);
            GUI.contentColor = oldColor;

            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();
            
            EditorGUILayout.Space(5);
        }
        
        private void DrawAIConnectionTab()
        {
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);

            // ─── Live MCP connection controls ───────────────────────────────
            // Previously the only entry points for these were Tools menu items
            // (Tools > Synaptic Pro > AI Reconnect / Auto Reconnect: Enable|Disable
            // / Join Discord). Surfacing them in the Setup window cuts the
            // discovery cost — users already open this window when troubleshooting.
            // MCP Server: Start/Stop stays in the Tools menu (advanced; the
            // typical workflow is to let Claude Desktop spawn the server).
            DrawConnectionControlsBar();

            // One-click startup
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("MCP Setup", EditorStyles.boldLabel);
            EditorGUILayout.Space(5);

            EditorGUILayout.LabelField("Once MCP setup is complete, Unity tools are immediately available in Claude Desktop", EditorStyles.wordWrappedLabel);
            
            EditorGUILayout.Space(10);
            
            // Display connection animation
            if (isConnecting)
            {
                DrawConnectingAnimation();
            }
            else if (!mcpConfigured)
            {
                // Setup not complete - show setup guide link
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Need help?", GUILayout.Width(70));
                if (GUILayout.Button("Setup Guide", GUILayout.Width(100)))
                {
                    Application.OpenURL("https://www.synaptic-ai.net/ja/docs/setup");
                }
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.Space(10);

                // AI Tool Selection (v1.1.0)
                EditorGUILayout.LabelField("Select Your AI Tool:", EditorStyles.boldLabel);
                EditorGUILayout.Space(5);

                var oldBgColor = GUI.backgroundColor;

                // Token SuperSave Mode (Recommended) - TOP
                GUI.backgroundColor = selectedAIClient == AIClientType.TokenSuperSaveMode
                    ? new Color(0.2f, 0.8f, 0.4f)
                    : new Color(0.85f, 1f, 0.85f);
                if (GUILayout.Button(
                    "★ Token SuperSave Mode [Recommended]\n" +
                    "(3 meta-tools only - 99% context reduction)",
                    GUILayout.Height(60)))
                {
                    selectedAIClient = AIClientType.TokenSuperSaveMode;
                }

                EditorGUILayout.Space(5);

                // Full Mode option
                GUI.backgroundColor = selectedAIClient == AIClientType.ClaudeDesktopOrCursor
                    ? new Color(0.3f, 0.7f, 0.9f)
                    : Color.white;
                if (GUILayout.Button(
                    "Full Mode\n" +
                    "(All 350+ tools exposed)",
                    GUILayout.Height(50)))
                {
                    selectedAIClient = AIClientType.ClaudeDesktopOrCursor;
                }

                EditorGUILayout.Space(5);

                // Essential Mode option
                GUI.backgroundColor = selectedAIClient == AIClientType.CursorOrLMStudioEssential
                    ? new Color(0.3f, 0.7f, 0.9f)
                    : Color.white;
                if (GUILayout.Button(
                    "Essential Mode\n" +
                    "(80 essential tools)",
                    GUILayout.Height(50)))
                {
                    selectedAIClient = AIClientType.CursorOrLMStudioEssential;
                }

                EditorGUILayout.Space(5);

                // Dynamic Mode option
                GUI.backgroundColor = selectedAIClient == AIClientType.GitHubCopilot
                    ? new Color(0.3f, 0.7f, 0.9f)
                    : Color.white;
                if (GUILayout.Button(
                    "Dynamic Mode\n" +
                    "(8 core tools + on-demand loading)",
                    GUILayout.Height(50)))
                {
                    selectedAIClient = AIClientType.GitHubCopilot;
                }

                GUI.backgroundColor = oldBgColor;

                EditorGUILayout.Space(5);

                // Info box based on selection
                if (selectedAIClient == AIClientType.TokenSuperSaveMode)
                {
                    EditorGUILayout.HelpBox(
                        "★ Recommended: Token SuperSave Mode\n\n" +
                        "Only 3 meta-tools for 99% context reduction:\n" +
                        "• list_categories() - Discover tool categories\n" +
                        "• list_tools(category) - See tools & parameters\n" +
                        "• execute(tool, params) - Run any of 350+ tools\n\n" +
                        "Works with all MCP clients. Best for long sessions.",
                        MessageType.Info);
                }
                else if (selectedAIClient == AIClientType.ClaudeDesktopOrCursor)
                {
                    EditorGUILayout.HelpBox(
                        "Full Mode: All 350+ Unity tools loaded at startup.\n" +
                        "• Higher context usage, but all tools immediately visible\n" +
                        "• Claude Desktop: Prompt caching helps with longer sessions",
                        MessageType.Info);
                }
                else if (selectedAIClient == AIClientType.CursorOrLMStudioEssential)
                {
                    EditorGUILayout.HelpBox(
                        "Essential Mode: 80 carefully selected tools (62% lighter).\n" +
                        "• Perfect for Cursor and LM Studio to avoid context bloat\n" +
                        "• Includes: GameObject, Camera, Scene, UI, Screenshot, Animation basics\n" +
                        "• Removed: Scripting, GOAP, Weather, Advanced VFX, Batch ops",
                        MessageType.Info);
                }
                else // GitHubCopilot
                {
                    EditorGUILayout.HelpBox(
                        "Dynamic Mode: Start with 8 tools, load more on-demand.\n" +
                        "• GitHub Copilot with MCP support\n" +
                        "• Use select_tools() to load additional tool categories\n" +
                        "• Perfect for avoiding tool limit warnings",
                        MessageType.Info);
                }

                EditorGUILayout.Space(10);

                // MCP Setup button
                var oldColor = GUI.backgroundColor;
                GUI.backgroundColor = new Color(0.2f, 0.6f, 0.8f);
                if (GUILayout.Button("Complete MCP Setup", setupButtonStyle, GUILayout.Height(60)))
                {
                    ConfigureMCP();
                }
                GUI.backgroundColor = oldColor;
            }
            else
            {
                // Setup complete
                EditorGUILayout.BeginHorizontal();

                var oldColor = GUI.backgroundColor;
                GUI.backgroundColor = new Color(0.2f, 0.8f, 0.2f);
                GUILayout.Button("✓ MCP Setup Complete", setupButtonStyle, GUILayout.Height(50));
                GUI.backgroundColor = oldColor;

                // Reconfigure button
                GUI.backgroundColor = new Color(0.8f, 0.6f, 0.2f);
                if (GUILayout.Button("🔄 Reconfigure", GUILayout.Width(100), GUILayout.Height(50)))
                {
                    ResetMCPConfiguration();
                }
                GUI.backgroundColor = oldColor;

                EditorGUILayout.EndHorizontal();

                EditorGUILayout.Space(10);

                // Display appropriate info based on selected mode (v1.1.0)
                string setupCompleteMessage;
                if (selectedAIClient == AIClientType.TokenSuperSaveMode)
                {
                    setupCompleteMessage =
                        "★ Setup complete! Token SuperSave Mode\n\n" +
                        "• 3 meta-tools → 350+ tools accessible\n" +
                        "• 99% context reduction for longer sessions\n\n" +
                        "Restart your AI tool, then ask:\n" +
                        "\"What Unity tools are available?\"";
                }
                else if (selectedAIClient == AIClientType.GitHubCopilot)
                {
                    setupCompleteMessage =
                        "Setup complete! Dynamic Mode (hub-server.js)\n" +
                        "• GitHub Copilot (.vscode/mcp.json)\n\n" +
                        "Restart VS Code to activate.\n" +
                        "Use select_tools() to load tool categories dynamically.";
                }
                else
                {
                    setupCompleteMessage =
                        "Setup complete! Full Mode (index.js) - All 246 tools\n" +
                        "• Claude Desktop\n" +
                        "• Cursor (~/.cursor/mcp.json)\n" +
                        "• VS Code (.vscode/mcp.json)\n\n" +
                        "Restart/Reload your AI tool to activate Unity MCP.";
                }

                EditorGUILayout.HelpBox(setupCompleteMessage, MessageType.Info);
            }

            EditorGUILayout.EndVertical();

            EditorGUILayout.Space(20);

            // How to Use
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("How to Use Unity Tools", EditorStyles.boldLabel);
            EditorGUILayout.Space(5);

            EditorGUILayout.LabelField("1. Open Claude Desktop / Cursor / VS Code", EditorStyles.wordWrappedLabel);
            EditorGUILayout.LabelField("2. Ask: \"What Unity tools are available?\"", EditorStyles.wordWrappedLabel);
            EditorGUILayout.LabelField("3. Give instructions: \"Create a red cube\" or \"Show me the scene hierarchy\"", EditorStyles.wordWrappedLabel);

            EditorGUILayout.Space(10);
            if (GUILayout.Button("Full Usage Guide", GUILayout.Height(35)))
            {
                ShowUsageGuide();
            }
            
            EditorGUILayout.EndVertical();
            
            // Auto-generated connection settings
            if (mcpServerRunning)
            {
                EditorGUILayout.Space(20);
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                GUILayout.Label("Connection Settings (Auto-generated)", EditorStyles.boldLabel);
                EditorGUILayout.Space(5);
                
                EditorGUILayout.LabelField("MCP Server: localhost:8090");
                EditorGUILayout.LabelField("Tool Name: unity-synaptic");
                
                EditorGUILayout.Space(10);
                EditorGUILayout.LabelField("💫 Usage:", EditorStyles.boldLabel);
                EditorGUILayout.LabelField("1. Open ChatGPT or Claude Desktop");
                EditorGUILayout.LabelField("2. Start a new chat");
                EditorGUILayout.LabelField("3. Tips for using tools:");
                EditorGUILayout.LabelField("   • Include words like \"tools\" or \"unity\"");
                EditorGUILayout.LabelField("   Example: \"Use unity tools to create a red cube\"");
                EditorGUILayout.LabelField("4. AI will automatically control Unity with MCP tools");
                
                EditorGUILayout.EndVertical();
            }
            
            EditorGUILayout.EndScrollView();
        }
        
        
        private void DrawServerManagementTab()
        {
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("MCP Server Management", EditorStyles.boldLabel);
            EditorGUILayout.Space(10);
            
            // Server status
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Server Status:");
            
            var statusColor = mcpServerRunning ? Color.green : Color.red;
            var statusText = mcpServerRunning ? "● Running" : "● Stopped";
            
            var oldColor = GUI.contentColor;
            GUI.contentColor = statusColor;
            GUILayout.Label(statusText);
            GUI.contentColor = oldColor;
            
            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();
            
            EditorGUILayout.Space(10);
            
            // Control buttons
            EditorGUILayout.BeginHorizontal();
            
            EditorGUI.BeginDisabledGroup(!mcpStatus?.isMCPInstalled ?? true);
            
            if (!mcpServerRunning)
            {
                if (GUILayout.Button("▶️ Start Server", GUILayout.Height(30)))
                {
                    StartMCPServer();
                }
            }
            else
            {
                if (GUILayout.Button("⏹️ Stop Server", GUILayout.Height(30)))
                {
                    StopMCPServer();
                }
            }
            
            if (GUILayout.Button("🔄 Restart", GUILayout.Height(30)))
            {
                RestartMCPServer();
            }
            
            EditorGUI.EndDisabledGroup();
            
            EditorGUILayout.EndHorizontal();
            
            EditorGUILayout.Space(20);
            
            // Server settings
            EditorGUILayout.Space(20);
            EditorGUILayout.LabelField("Server Settings:", EditorStyles.boldLabel);
            EditorGUI.indentLevel++;
            
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("MCP Port:", GUILayout.Width(100));
            mcpPort = EditorGUILayout.IntField(mcpPort);
            EditorGUILayout.EndHorizontal();
            
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("WebSocket Port:", GUILayout.Width(100));
            wsPort = EditorGUILayout.IntField(wsPort);
            EditorGUILayout.EndHorizontal();
            
            EditorGUI.indentLevel--;
            
            // Connection Info
            if (mcpStatus?.isMCPInstalled ?? false)
            {
                EditorGUILayout.Space(10);
                EditorGUILayout.LabelField("Connection Info:", EditorStyles.boldLabel);
                EditorGUI.indentLevel++;
                EditorGUILayout.LabelField($"MCP: localhost:{mcpPort}");
                EditorGUILayout.LabelField($"WebSocket: ws://localhost:{wsPort}");
                EditorGUILayout.LabelField($"Accessible from Desktop AI");
                EditorGUI.indentLevel--;
            }
            
            EditorGUILayout.EndVertical();
            
            // Log Viewer
            EditorGUILayout.Space(20);
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("Server Log", EditorStyles.boldLabel);
            
            // Display server logs here
            EditorGUILayout.TextArea("Server logs will be displayed here...", GUILayout.Height(200));
            
            EditorGUILayout.EndVertical();
        }
        
        /* Planned for future implementation
        private void DrawCLIConfigTab()
        {
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
            
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("CLI AI Configuration Manager", EditorStyles.boldLabel);
            EditorGUILayout.Space(10);

            EditorGUILayout.LabelField("Batch create configuration files for various CLI AI tools", EditorStyles.wordWrappedLabel);
            EditorGUILayout.Space(10);
            
            // Claude Code configuration (2025 MCP specification)
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("Claude Code (Anthropic)", EditorStyles.boldLabel);
            EditorGUILayout.LabelField("Official CLI for Claude with MCP support", EditorStyles.miniLabel);
            EditorGUILayout.Space(5);
            
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Configure MCP", GUILayout.Height(30)))
            {
                GenerateClaudeCodeConfig();
            }
            if (GUILayout.Button("Docs", GUILayout.Width(60), GUILayout.Height(30)))
            {
                Application.OpenURL("https://docs.anthropic.com/en/docs/claude-code/mcp");
            }
            EditorGUILayout.EndHorizontal();
            
            EditorGUILayout.LabelField("Config: .claude/settings.local.json", EditorStyles.miniLabel);
            EditorGUILayout.EndVertical();
            
            EditorGUILayout.Space(10);
            
            
            // Cursor settings (2025 Popular MCP Client)
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("Cursor (Anysphere)", EditorStyles.boldLabel);
            EditorGUILayout.LabelField("AI-powered code editor with MCP support", EditorStyles.miniLabel);
            EditorGUILayout.Space(5);
            
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Configure MCP", GUILayout.Height(30)))
            {
                if (GenerateCursorConfig())
                {
                    EditorUtility.DisplayDialog(
                        "Cursor Setup Complete",
                        "Cursor MCP configuration created successfully!\n\n" +
                        "Config file: ~/.cursor/mcp.json\n\n" +
                        "Next steps:\n" +
                        "1. Reload MCP Servers in Cursor:\n" +
                        "   Settings → MCP Servers → Reload\n" +
                        "2. Unity tools will be available in Cursor",
                        "OK"
                    );
                }
                else
                {
                    EditorUtility.DisplayDialog(
                        "Cursor Setup Failed",
                        "Failed to create Cursor configuration.\n\n" +
                        "Please check the Console for details.",
                        "OK"
                    );
                }
            }
            if (GUILayout.Button("Docs", GUILayout.Width(60), GUILayout.Height(30)))
            {
                Application.OpenURL("https://www.synaptic-ai.net/ja/docs/setup#cursor");
            }
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.LabelField("Config: ~/.cursor/mcp.json", EditorStyles.miniLabel);
            EditorGUILayout.EndVertical();

            EditorGUILayout.Space(10);

            // VS Code settings (Claude Code extension)
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("VS Code (Microsoft)", EditorStyles.boldLabel);
            EditorGUILayout.LabelField("Visual Studio Code with Claude Code extension MCP support", EditorStyles.miniLabel);
            EditorGUILayout.Space(5);

            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Configure MCP", GUILayout.Height(30)))
            {
                if (GenerateVSCodeConfig())
                {
                    EditorUtility.DisplayDialog(
                        "VS Code Setup Complete",
                        "VS Code MCP configuration created successfully!\n\n" +
                        "Config file: .vscode/mcp.json\n\n" +
                        "Next steps:\n" +
                        "1. Reload VS Code window:\n" +
                        "   Cmd/Ctrl + Shift + P → 'Reload Window'\n" +
                        "2. Unity tools will be available in Claude Code",
                        "OK"
                    );
                }
                else
                {
                    EditorUtility.DisplayDialog(
                        "VS Code Setup Failed",
                        "Failed to create VS Code configuration.\n\n" +
                        "Please check the Console for details.",
                        "OK"
                    );
                }
            }
            if (GUILayout.Button("Docs", GUILayout.Width(60), GUILayout.Height(30)))
            {
                Application.OpenURL("https://www.synaptic-ai.net/ja/docs/setup#vscode");
            }
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.LabelField("Config: .vscode/mcp.json", EditorStyles.miniLabel);
            EditorGUILayout.EndVertical();

            EditorGUILayout.Space(10);

            // Windsurf settings (2025 MCP Client)
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("Windsurf (Codeium)", EditorStyles.boldLabel);
            EditorGUILayout.LabelField("The IDE that writes with you - MCP enabled", EditorStyles.miniLabel);
            EditorGUILayout.Space(5);
            
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Configure MCP", GUILayout.Height(30)))
            {
                GenerateWindsurfConfig();
            }
            if (GUILayout.Button("Docs", GUILayout.Width(60), GUILayout.Height(30)))
            {
                Application.OpenURL("https://codeium.com/windsurf");
            }
            EditorGUILayout.EndHorizontal();
            
            EditorGUILayout.LabelField("Config: ~/.windsurf/mcp_servers.json", EditorStyles.miniLabel);
            EditorGUILayout.EndVertical();
            
            EditorGUILayout.Space(20);

            // Batch settings
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("Batch Configuration", EditorStyles.boldLabel);
            EditorGUILayout.Space(5);
            
            EditorGUILayout.LabelField("Configure all supported MCP clients at once", EditorStyles.wordWrappedLabel);
            EditorGUILayout.Space(10);
            
            var oldColor = GUI.backgroundColor;
            GUI.backgroundColor = new Color(0.2f, 0.8f, 0.2f);
            if (GUILayout.Button("Configure All MCP Clients", GUILayout.Height(40)))
            {
                GenerateAllCLIConfigs();
            }
            GUI.backgroundColor = oldColor;
            
            EditorGUILayout.EndVertical();
            
            EditorGUILayout.Space(20);
            
            // File watch settings
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("File Watch Settings", EditorStyles.boldLabel);
            EditorGUILayout.Space(5);

            EditorGUILayout.LabelField("Monitor project file changes and notify AI", EditorStyles.wordWrappedLabel);
            EditorGUILayout.Space(10);

            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Create Watch Configuration", GUILayout.Height(30)))
            {
                GenerateWatchConfig();
            }
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.LabelField("Monitored files: .cs, .js, .ts, .json, .md", EditorStyles.miniLabel);
            
            EditorGUILayout.EndVertical();

            EditorGUILayout.EndVertical();
            EditorGUILayout.EndScrollView();
        }
        */

        private void DrawHTTPServerTab()
        {
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);

            // HTTP Server Section
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("HTTP Server", EditorStyles.boldLabel);
            EditorGUILayout.Space(5);

            EditorGUILayout.HelpBox(
                "HTTP Server allows direct API access to Unity tools.\n" +
                "Use this for custom integrations, testing, or when MCP is not available.",
                MessageType.Info);

            EditorGUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            if (GUILayout.Button("CLI Integration Guide", GUILayout.Width(150)))
            {
                Application.OpenURL("https://www.synaptic-ai.net/ja/docs/cli-integration");
            }
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Space(10);

            // External HTTP Server UI
            DrawExternalHTTPServerUI();

            EditorGUILayout.EndVertical();

            // API Endpoints Section
            httpServerRunning = externalHttpRunning;
            if (httpServerRunning)
            {
                EditorGUILayout.Space(15);
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                GUILayout.Label("API Endpoints", EditorStyles.boldLabel);
                EditorGUILayout.Space(5);

                var baseUrl = $"http://localhost:{httpPort}";

                DrawEndpointRow("Root (Prompt)", "GET", $"{baseUrl}/");
                DrawEndpointRow("Health Check", "GET", $"{baseUrl}/health");
                DrawEndpointRow("AI Prompt", "GET", $"{baseUrl}/prompt");
                DrawEndpointRow("List Tools", "GET", $"{baseUrl}/tools");
                DrawEndpointRow("Categories", "GET", $"{baseUrl}/categories");
                DrawEndpointRow("Tool Search", "GET", $"{baseUrl}/tools/search?q=");
                DrawEndpointRow("Tools Reference", "GET", $"{baseUrl}/tools/reference");
                DrawEndpointRow("Resources", "GET", $"{baseUrl}/resources");
                DrawEndpointRow("Execute Tool", "POST", $"{baseUrl}/execute");
                DrawEndpointRow("Batch Execute", "POST", $"{baseUrl}/batch");

                EditorGUILayout.Space(10);

                if (GUILayout.Button("Copy Base URL", GUILayout.Height(25)))
                {
                    GUIUtility.systemCopyBuffer = baseUrl;
                    SynLog.Info($"Copied: {baseUrl}");
                }

                EditorGUILayout.EndVertical();
            }

            // Usage Example
            EditorGUILayout.Space(15);
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("Usage Example", EditorStyles.boldLabel);
            EditorGUILayout.Space(5);

            EditorGUILayout.LabelField("cURL Example:", EditorStyles.boldLabel);
            var curlExample = $"curl http://localhost:{httpPort}/health";
            EditorGUILayout.SelectableLabel(curlExample, EditorStyles.textField, GUILayout.Height(20));

            EditorGUILayout.Space(5);
            EditorGUILayout.LabelField("Execute Tool (Recommended):", EditorStyles.boldLabel);
            var toolExample = $"curl -X POST http://localhost:{httpPort}/execute \\\n  -H \"Content-Type: application/json\" \\\n  -d '{{\"tool\": \"unity_create_gameobject\", \"params\": {{\"name\": \"MyCube\", \"type\": \"cube\"}}}}'";
            EditorGUILayout.SelectableLabel(toolExample, EditorStyles.textArea, GUILayout.Height(50));

            EditorGUILayout.Space(5);
            EditorGUILayout.LabelField("Batch Execute:", EditorStyles.boldLabel);
            var batchExample = $"curl -X POST http://localhost:{httpPort}/batch \\\n  -H \"Content-Type: application/json\" \\\n  -d '[{{\"tool\": \"unity_create_gameobject\", \"params\": {{\"name\": \"Obj1\", \"type\": \"cube\"}}}}, ...]'";
            EditorGUILayout.SelectableLabel(batchExample, EditorStyles.textArea, GUILayout.Height(50));

            EditorGUILayout.EndVertical();

            // AI Prompt Section
            EditorGUILayout.Space(15);
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("AI Control Prompt", EditorStyles.boldLabel);
            EditorGUILayout.Space(5);

            EditorGUILayout.HelpBox(
                "Copy this prompt to your AI (Claude Code, Codex CLI, etc.) to enable HTTP control.\n" +
                $"Or fetch directly: curl http://localhost:{httpPort}/",
                MessageType.Info);

            EditorGUILayout.Space(10);

            if (GUILayout.Button("Copy AI Prompt to Clipboard", GUILayout.Height(30)))
            {
                var mcpServerPath = FindMCPServerPath();
                var aiPrompt = GetHTTPControlPrompt(mcpServerPath, httpPort);
                GUIUtility.systemCopyBuffer = aiPrompt;
                SynLog.Info("[Synaptic] AI Prompt copied to clipboard!");
                EditorUtility.DisplayDialog("Copied!", "AI Control Prompt has been copied to clipboard.\n\nPaste it to your AI assistant to enable HTTP control.", "OK");
            }

            EditorGUILayout.EndVertical();

            // ========== ログ出力設定 ==========
            EditorGUILayout.Space(15);
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("Log Output", EditorStyles.boldLabel);
            EditorGUILayout.Space(5);

            bool currentVerbose = SynapticAIPro.SynLog.VerboseEnabled;
            bool newVerbose = EditorGUILayout.ToggleLeft(
                "Verbose Logs (Info / Warning)",
                currentVerbose
            );
            if (newVerbose != currentVerbose)
            {
                SynapticAIPro.SynLog.VerboseEnabled = newVerbose;
            }
            EditorGUILayout.LabelField(
                "オフにすると Synaptic AI Pro 関連の Info/Warning ログをコンソールに出力しません（Errorは常に表示）",
                EditorStyles.wordWrappedMiniLabel
            );

            EditorGUILayout.EndVertical();

            EditorGUILayout.EndScrollView();
        }

        private double lastHttpStatusCheckTime = 0;

        private void DrawExternalHTTPServerUI()
        {
            // Server Status（5秒ごとにチェック。毎フレームのTCP接続を防ぐ）
            if (EditorApplication.timeSinceStartup - lastHttpStatusCheckTime > 5.0)
            {
                lastHttpStatusCheckTime = EditorApplication.timeSinceStartup;
                CheckExternalHttpServerStatus();
            }

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Status:", GUILayout.Width(60));

            var statusColor = externalHttpRunning ? Color.green : Color.gray;
            var statusText = externalHttpRunning ? "● Running (Node.js)" : "● Stopped";

            var oldColor = GUI.contentColor;
            GUI.contentColor = statusColor;
            GUILayout.Label(statusText, EditorStyles.boldLabel);
            GUI.contentColor = oldColor;

            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Space(5);

            // Port Setting
            EditorGUI.BeginDisabledGroup(externalHttpRunning);

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("HTTP Port:", GUILayout.Width(80));
            httpPort = EditorGUILayout.IntField(httpPort, GUILayout.Width(80));
            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();

            EditorGUI.EndDisabledGroup();

            EditorGUILayout.Space(5);

            // Auto-Start Toggle
            EditorGUILayout.BeginHorizontal();
            var autoStart = HttpAutoStartEnabled;
            var newAutoStart = EditorGUILayout.Toggle("Auto-Start on Load", autoStart);
            if (newAutoStart != autoStart)
            {
                HttpAutoStartEnabled = newAutoStart;
            }
            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.Space(10);

            // Control Buttons
            EditorGUILayout.BeginHorizontal();

            if (!externalHttpRunning)
            {
                var startBgColor = GUI.backgroundColor;
                GUI.backgroundColor = new Color(0.2f, 0.7f, 0.3f);
                if (GUILayout.Button("Start HTTP Server", GUILayout.Height(35)))
                {
                    StartExternalHttpServer();
                }
                GUI.backgroundColor = startBgColor;
            }
            else
            {
                var stopBgColor = GUI.backgroundColor;
                GUI.backgroundColor = new Color(0.8f, 0.3f, 0.3f);
                if (GUILayout.Button("Stop HTTP Server", GUILayout.Height(35)))
                {
                    StopExternalHttpServer();
                }
                GUI.backgroundColor = stopBgColor;
            }

            EditorGUILayout.EndHorizontal();

            // Connect status / Connect button
            EditorGUILayout.Space(5);
            var wsConnected = NexusHTTPWebSocketClient.Instance?.IsConnected ?? false;
            // GUILayout構造を常に同じにする（Layout/Repaintフェーズ不一致防止）
            EditorGUI.BeginDisabledGroup(wsConnected);
            if (GUILayout.Button(
                wsConnected ? $"✓ Unity connected (port {httpPort})" : "Connect Unity Only (Server already running)",
                GUILayout.Height(28)))
            {
                if (!wsConnected)
                {
                    _ = ConnectToHttpServerAsync(httpPort);
                }
            }
            EditorGUI.EndDisabledGroup();

            // Info about external mode
            EditorGUILayout.Space(5);
            EditorGUILayout.HelpBox(
                "External mode runs http-server.js via Node.js.\n" +
                "Benefits: Stable across domain reloads, Play mode changes.\n" +
                "HTTP and WebSocket use the same port.",
                MessageType.None);
        }

        // ===== External HTTP Server Process Management =====

        private void CheckExternalHttpServerStatus()
        {
            // Check if process is still running
            if (externalHttpProcess != null)
            {
                try
                {
                    if (externalHttpProcess.HasExited)
                    {
                        externalHttpProcess = null;
                        externalHttpRunning = false;
                    }
                    else
                    {
                        externalHttpRunning = true;
                        return;
                    }
                }
                catch
                {
                    externalHttpProcess = null;
                    externalHttpRunning = false;
                }
            }

            // No local process handle (fresh domain reload, or never-started).
            // Probe the port on a background thread and cache the result. OnGUI must
            // never block on a TCP connect — a 500ms stall per repaint freezes the editor.
            if (portCheckInFlight) return;
            double now = EditorApplication.timeSinceStartup;
            if (now - lastPortCheckTime < PORT_CHECK_INTERVAL_SEC) return;

            lastPortCheckTime = now;
            portCheckInFlight = true;
            int portToCheck = httpPort;

            _ = Task.Run(async () =>
            {
                bool listening = false;
                try
                {
                    using (var tcp = new System.Net.Sockets.TcpClient())
                    {
                        var connectTask = tcp.ConnectAsync("localhost", portToCheck);
                        var winner = await Task.WhenAny(connectTask, Task.Delay(PORT_CHECK_TIMEOUT_MS));
                        if (winner == connectTask)
                        {
                            try { await connectTask; listening = tcp.Connected; }
                            catch { listening = false; }
                        }
                    }
                }
                catch { listening = false; }

                // Marshal state + Repaint back to the main thread.
                EditorApplication.delayCall += () =>
                {
                    portCheckInFlight = false;
                    if (externalHttpRunning != listening)
                    {
                        externalHttpRunning = listening;
                        if (this) Repaint();
                    }
                };
            });
        }

        private bool IsPortListening(int port)
        {
            // Quick TCP check with short timeout (avoid blocking UI thread)
            try
            {
                using (var tcp = new System.Net.Sockets.TcpClient())
                {
                    var result = tcp.BeginConnect("localhost", port, null, null);
                    bool connected = result.AsyncWaitHandle.WaitOne(500); // 500msタイムアウト
                    if (connected && tcp.Connected)
                    {
                        tcp.EndConnect(result);
                        return true;
                    }
                    return false;
                }
            }
            catch
            {
                return false;
            }
        }

        private void StartExternalHttpServer()
        {
            var mcpServerPath = FindMCPServerPath();
            var httpServerScript = Path.Combine(mcpServerPath, "http-server.js");

            if (!File.Exists(httpServerScript))
            {
                EditorUtility.DisplayDialog("Error",
                    $"http-server.js not found at:\n{httpServerScript}\n\nPlease ensure Synaptic AI Pro is properly installed.",
                    "OK");
                return;
            }

            // Find Node.js path
            var nodePath = FindNodePath();
            if (string.IsNullOrEmpty(nodePath))
            {
                EditorUtility.DisplayDialog("Error",
                    "Node.js not found.\n\nPlease install Node.js from https://nodejs.org/",
                    "OK");
                return;
            }

            try
            {
                System.Diagnostics.ProcessStartInfo startInfo;

                if (Application.platform == RuntimePlatform.WindowsEditor)
                {
                    // Windows: detached from Unity's Job Object via CreateProcessW
                    // with CREATE_BREAKAWAY_FROM_JOB. Process.Start inherits the
                    // Job and gets killed on assembly reload — see ESC-0095.
                    string logDir = Path.Combine(mcpServerPath, "logs");
                    try { Directory.CreateDirectory(logDir); } catch { }
                    string logFile = Path.Combine(logDir, "http-server.log");

                    int pid = SynapticDetachedProcess.StartWindows(
                        nodePath, httpServerScript, httpPort, mcpServerPath, logFile);

                    if (pid == 0)
                    {
                        SynLog.Info("[Synaptic] Detached spawn failed, falling back to Process.Start");
                        // Fall through to legacy path below
                        startInfo = new System.Diagnostics.ProcessStartInfo
                        {
                            FileName = nodePath,
                            Arguments = $"\"{httpServerScript}\" {httpPort}",
                            WorkingDirectory = mcpServerPath,
                            UseShellExecute = false,
                            RedirectStandardOutput = true,
                            RedirectStandardError = true,
                            CreateNoWindow = true,
                            StandardOutputEncoding = System.Text.Encoding.UTF8,
                            StandardErrorEncoding = System.Text.Encoding.UTF8
                        };
                        startInfo.EnvironmentVariables["HTTP_PORT"] = httpPort.ToString();
                    }
                    else
                    {
                        // Detached path: process is independent of Unity's Job.
                        // We don't keep externalHttpProcess (no handle) — recovery
                        // uses SessionState PID. Mark running and connect.
                        externalHttpProcess = null;
                        externalHttpRunning = true;
                        EditorPrefs.SetInt(PREF_HTTP_PORT, httpPort);
                        SynLog.Info($"[Synaptic] External HTTP Server started detached (PID={pid}) on port {httpPort}");
                        SynLog.Info($"[Synaptic] Node: {nodePath}");
                        SynLog.Info($"[Synaptic] Script: {httpServerScript}");
                        SynLog.Info($"[Synaptic] Log: {logFile}");
                        _ = ConnectToHttpServerAsync(httpPort);
                        return;
                    }
                }
                else
                {
                    // macOS/Linux: 直接起動
                    //
                    // Previous implementation piped stdout/stderr back to C#
                    // (RedirectStandardOutput/Error + BeginOutputReadLine).
                    // When Unity's C# domain reloads (recompile), the pipe
                    // readers on the C# side disappear; the node process's
                    // next stdout write then hits SIGPIPE and node terminates.
                    // Result: HTTP server died every time a script was edited.
                    //
                    // Fix: launch via `sh -c "nohup node ... >log 2>&1 &"` so
                    // the child is fully detached from Unity's pipes and
                    // process group, mirroring the Windows detached path.
                    string logDir = Path.Combine(mcpServerPath, "logs");
                    try { Directory.CreateDirectory(logDir); } catch { }
                    string logFile = Path.Combine(logDir, "http-server.log");

                    // sh -c is portable to both macOS (BSD sh) and Linux.
                    // Quote the script path; quote the log path; redirect both
                    // streams to the log file; trailing `&` to detach.
                    string escapedScript = httpServerScript.Replace("\"", "\\\"");
                    string escapedLog = logFile.Replace("\"", "\\\"");
                    string shellCmd =
                        $"nohup \"{nodePath}\" \"{escapedScript}\" {httpPort} " +
                        $">\"{escapedLog}\" 2>&1 </dev/null &";

                    startInfo = new System.Diagnostics.ProcessStartInfo
                    {
                        FileName = "/bin/sh",
                        Arguments = $"-c \"{shellCmd.Replace("\"", "\\\"")}\"",
                        WorkingDirectory = mcpServerPath,
                        UseShellExecute = false,
                        RedirectStandardOutput = false,
                        RedirectStandardError = false,
                        CreateNoWindow = true,
                    };
                    startInfo.EnvironmentVariables["HTTP_PORT"] = httpPort.ToString();

                    var detachProc = new System.Diagnostics.Process { StartInfo = startInfo };
                    detachProc.Start();
                    detachProc.WaitForExit(); // sh exits immediately after backgrounding node
                    detachProc.Dispose();

                    // We have no handle to the actual node process — by design,
                    // so that domain reload can't kill it. Recovery on next
                    // load uses port-listen probe in RestoreDetachedHttpServerOnReload.
                    externalHttpProcess = null;
                    externalHttpRunning = true;
                    EditorPrefs.SetInt(PREF_HTTP_PORT, httpPort);
                    SynLog.Info($"[Synaptic] External HTTP Server detach-spawned on port {httpPort}");
                    SynLog.Info($"[Synaptic] Node: {nodePath}");
                    SynLog.Info($"[Synaptic] Script: {httpServerScript}");
                    SynLog.Info($"[Synaptic] Log: {logFile}");

                    _ = ConnectToHttpServerAsync(httpPort);
                    return;
                }

                externalHttpProcess = new System.Diagnostics.Process { StartInfo = startInfo };

                externalHttpProcess.OutputDataReceived += (sender, e) =>
                {
                    if (!string.IsNullOrEmpty(e.Data))
                        SynLog.Info($"[HTTP Server] {e.Data}");
                };
                externalHttpProcess.ErrorDataReceived += (sender, e) =>
                {
                    if (!string.IsNullOrEmpty(e.Data))
                        SynLog.Info($"[HTTP Server] {e.Data}");
                };

                externalHttpProcess.Start();
                externalHttpProcess.BeginOutputReadLine();
                externalHttpProcess.BeginErrorReadLine();

                externalHttpRunning = true;
                EditorPrefs.SetInt(PREF_HTTP_PORT, httpPort);

                SynLog.Info($"[Synaptic] External HTTP Server started on port {httpPort}");
                SynLog.Info($"[Synaptic] Node: {nodePath}");
                SynLog.Info($"[Synaptic] Script: {httpServerScript}");

                // Connect Unity to HTTP Server via WebSocket (with delay to let server start)
                _ = ConnectToHttpServerAsync(httpPort);
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] Failed to start external HTTP server: {e.Message}");
                EditorUtility.DisplayDialog("Error", $"Failed to start HTTP server:\n{e.Message}", "OK");
                externalHttpProcess = null;
                externalHttpRunning = false;
            }
        }

        private async Task ConnectToHttpServerAsync(int port)
        {
            // Wait for HTTP Server to start (Windows needs more time via cmd.exe)
            var waitTime = Application.platform == RuntimePlatform.WindowsEditor ? 3000 : 1500;
            await Task.Delay(waitTime);

            // Retry connection with increasing delays
            for (int i = 0; i < 3; i++)
            {
                var connected = await NexusHTTPWebSocketClient.Instance.Connect(port);
                if (connected)
                {
                    SynLog.Info($"[Synaptic] Unity connected to HTTP Server on port {port}");
                    return;
                }
                SynLog.Info($"[Synaptic] Connection attempt {i + 1}/3 failed, retrying...");
                await Task.Delay(2000);
            }

            SynLog.Warn($"[Synaptic] Failed to connect Unity to HTTP Server after 3 attempts.\nTry starting manually: cd to MCPServer folder and run 'node http-server.js {port}'");
        }

        private void StopExternalHttpServer()
        {
            // Detached path: kill by stored PID (no Process handle exists)
            if (Application.platform == RuntimePlatform.WindowsEditor &&
                externalHttpProcess == null && externalHttpRunning)
            {
                if (SynapticDetachedProcess.KillStored())
                {
                    externalHttpRunning = false;
                    SynLog.Info("[Synaptic] Detached HTTP server stopped.");
                    return;
                }
            }

            // Kill process first (WebSocket will disconnect automatically)
            if (externalHttpProcess != null)
            {
                try
                {
                    if (!externalHttpProcess.HasExited)
                    {
                        externalHttpProcess.Kill();
                        externalHttpProcess.WaitForExit(3000);
                    }
                    externalHttpProcess.Dispose();
                }
                catch (Exception e)
                {
                    SynLog.Warn($"[Synaptic] Error stopping HTTP server: {e.Message}");
                }
                finally
                {
                    externalHttpProcess = null;
                    externalHttpRunning = false;
                }
            }
            else if (externalHttpRunning)
            {
                // Process reference lost (e.g., after domain reload)
                // Kill by port number instead
                KillProcessOnPortSafe(httpPort);
                externalHttpRunning = false;
                SynLog.Info($"[Synaptic] HTTP Server on port {httpPort} - process reference lost. Killing by port.");
            }

            SynLog.Info("[Synaptic] External HTTP Server stopped");
        }

        private void KillProcessOnPortSafe(int port)
        {
            // Run in a separate thread to avoid blocking Unity
            System.Threading.ThreadPool.QueueUserWorkItem(_ =>
            {
                try
                {
                    KillProcessOnPort(port);
                }
                catch (Exception e)
                {
                    SynLog.Warn($"[Synaptic] Could not kill process on port {port}: {e.Message}");
                }
            });
        }

        private void KillProcessOnPort(int port)
        {
            try
            {
                if (Application.platform == RuntimePlatform.OSXEditor)
                {
                    // macOS: lsof + kill
                    var lsofProcess = new System.Diagnostics.Process
                    {
                        StartInfo = new System.Diagnostics.ProcessStartInfo
                        {
                            FileName = "/bin/bash",
                            Arguments = $"-c \"lsof -ti :{port} | xargs kill -9 2>/dev/null\"",
                            UseShellExecute = false,
                            CreateNoWindow = true,
                            RedirectStandardOutput = true,
                            RedirectStandardError = true
                        }
                    };
                    lsofProcess.Start();
                    lsofProcess.WaitForExit(3000);
                }
                else if (Application.platform == RuntimePlatform.WindowsEditor)
                {
                    // Windows: netstat + taskkill
                    var process = new System.Diagnostics.Process
                    {
                        StartInfo = new System.Diagnostics.ProcessStartInfo
                        {
                            FileName = "cmd.exe",
                            Arguments = $"/c \"for /f \"tokens=5\" %a in ('netstat -aon ^| findstr :{port} ^| findstr LISTENING') do taskkill /PID %a /F\"",
                            UseShellExecute = false,
                            CreateNoWindow = true
                        }
                    };
                    process.Start();
                    process.WaitForExit(3000);
                }
            }
            catch (Exception e)
            {
                SynLog.Warn($"[Synaptic] Failed to kill process on port {port}: {e.Message}");
            }
        }

        private string GetHTTPControlPrompt(string mcpServerPath, int port)
        {
            return $@"# Synaptic AI Pro (Unity) HTTP Control Instructions

## Prerequisites
- Unity must be open with Synaptic AI Pro project loaded
- HTTP Server is running (started from this window or auto-start enabled)
- No external processes needed - server runs inside Unity

## Endpoints
- GET /health - Server status
- GET /prompt - Get this AI control prompt
- GET /categories - List all tool categories
- GET /tools/category/:cat - List tools in category with inputSchema
- GET /tools - Full tool registry
- POST /execute - Execute single tool (RECOMMENDED)
- POST /batch - Execute multiple tools at once (RECOMMENDED)
- POST /tool/:toolName - Execute tool (legacy)

## Verify connection
curl http://localhost:{port}/health

## Tool discovery
curl http://localhost:{port}/categories
curl http://localhost:{port}/tools/category/scene

## Single tool execution (RECOMMENDED)
curl -X POST http://localhost:{port}/execute -H ""Content-Type: application/json"" -d '{{""tool"":""unity_create_gameobject"",""params"":{{""name"":""MyCube"",""type"":""cube""}}}}'

## Batch execution (RECOMMENDED for multiple operations)
curl -X POST http://localhost:{port}/batch -H ""Content-Type: application/json"" -d '[
  {{""tool"":""unity_create_gameobject"",""params"":{{""name"":""Cube1"",""type"":""cube""}}}},
  {{""tool"":""unity_set_transform"",""params"":{{""name"":""Cube1"",""position"":""2,0,0""}}}},
  {{""tool"":""unity_create_gameobject"",""params"":{{""name"":""Sphere1"",""type"":""sphere""}}}}
]'

## If connection fails
- Connection refused → Unity not open or HTTP Server not started
- Start HTTP Server from: Tools > Synaptic Pro > Synaptic Setup > HTTP Server tab
- Or enable ""Auto-Start on Load"" for automatic startup

## Note for Codex CLI
CRITICAL: Run curl commands EXACTLY as shown. Do NOT add nice, nohup, redirects (>), or other modifications.
If you get ""nice(5) failed"" or similar sandbox errors, use escalation (request additional permission from user).
Sandbox may block localhost connections. Use escalation if curl commands fail.

## Notes
- All responses are JSON
- Use /batch for multiple operations (more efficient)
- 30 second timeout per request
";
        }

        private void DrawEndpointRow(string name, string method, string url)
        {
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField(name, GUILayout.Width(100));
            EditorGUILayout.LabelField(method, EditorStyles.miniLabel, GUILayout.Width(40));
            EditorGUILayout.SelectableLabel(url, EditorStyles.textField, GUILayout.Height(18));
            EditorGUILayout.EndHorizontal();
        }

        private void DrawHelpTab()
        {
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
            
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            GUILayout.Label("AI Connection Help", EditorStyles.boldLabel);
            EditorGUILayout.Space(10);
            
            // Simple description
            DrawHelpSection("What is Synaptic Pro?",
                "A tool that connects Unity with desktop AI apps like Claude, Gemini, and more.\n" +
                "No complex setup required - get started with one click.");
            
            // How to use
            DrawHelpSection("How to Use",
                "1. Click 'Start AI Connection' in the AI Connection tab\n" +
                "2. Open Claude/Gemini desktop app\n" +
                "3. Connect to localhost:3000 in AI app settings\n" +
                "4. AI is now available in Unity!");
            
            // Supported AI apps
            DrawHelpSection("Supported AI Apps",
                "• Claude Desktop (Recommended)\n" +
                "• Cursor / Windsurf\n" +
                "• VS Code (GitHub Copilot)\n" +
                "• Gemini CLI / Codex CLI\n" +
                "• Other MCP-compatible AI apps");
            
            // Troubleshooting
            DrawHelpSection("When Things Don't Work",
                "• Error when clicking 'Start AI Connection'\n" +
                "  → Run Unity as administrator\n\n" +
                "• Cannot connect from AI app\n" +
                "  → Check firewall settings\n\n" +
                "• Connection succeeds but cannot control Unity\n" +
                "  → Confirm 'Start AI Connection' is pressed in Unity");
            
            // Links
            EditorGUILayout.Space(20);
            GUILayout.Label("Documentation", EditorStyles.boldLabel);

            if (GUILayout.Button("Setup Guide"))
            {
                Application.OpenURL("https://www.synaptic-ai.net/ja/docs/setup");
            }

            if (GUILayout.Button("CLI Integration"))
            {
                Application.OpenURL("https://www.synaptic-ai.net/ja/docs/cli-integration");
            }

            if (GUILayout.Button("Discord Community"))
            {
                Application.OpenURL("https://discord.gg/MXwHCVWmPe");
            }
            
            EditorGUILayout.EndVertical();
            EditorGUILayout.EndScrollView();
        }
        
        private void DrawStatusItem(string label, bool isInstalled, string version)
        {
            EditorGUILayout.BeginHorizontal();
            
            var icon = isInstalled ? "✅" : "❌";
            var color = isInstalled ? Color.green : Color.red;
            
            var oldColor = GUI.contentColor;
            GUI.contentColor = color;
            GUILayout.Label(icon, GUILayout.Width(20));
            GUI.contentColor = oldColor;
            
            EditorGUILayout.LabelField(label, GUILayout.Width(100));
            
            if (!string.IsNullOrEmpty(version))
            {
                EditorGUILayout.LabelField(version, EditorStyles.miniLabel);
            }
            
            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();
        }
        
        private void DrawHelpSection(string title, string content)
        {
            GUILayout.Label(title, EditorStyles.boldLabel);
            EditorGUI.indentLevel++;
            EditorGUILayout.LabelField(content, EditorStyles.wordWrappedLabel);
            EditorGUI.indentLevel--;
            EditorGUILayout.Space(10);
        }
        
        private void DrawConnectingAnimation()
        {
            // Animation box
            EditorGUILayout.BeginVertical(EditorStyles.helpBox);

            // Rotating spinner
            var spinnerChars = new string[] { "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" };
            var spinnerIndex = (int)(animationTime * 10) % spinnerChars.Length;

            // Current message (fixed to avoid looping)
            var messageIndex = Mathf.Min((int)(animationTime / 3), connectingMessages.Length - 1);
            var currentMessage = connectingMessages[messageIndex];
            
            // Animation display
            var animatedText = $"{spinnerChars[spinnerIndex]} {currentMessage}...";

            var centeredStyle = new GUIStyle(EditorStyles.boldLabel)
            {
                alignment = TextAnchor.MiddleCenter,
                fontSize = 16
            };

            GUILayout.Label(animatedText, centeredStyle, GUILayout.Height(60));

            // Progress bar (100% at the last message)
            var progress = (messageIndex + 1f) / connectingMessages.Length;
            var rect = GUILayoutUtility.GetRect(0, 4, GUILayout.ExpandWidth(true));
            EditorGUI.ProgressBar(rect, progress, "");
            
            // Cancel button
            EditorGUILayout.Space(10);
            if (GUILayout.Button("⏹️ Cancel", GUILayout.Height(30)))
            {
                isConnecting = false;
                SynLog.Info("[Synaptic] AI connection cancelled");
                Repaint();
            }
            
            EditorGUILayout.EndVertical();
        }
        
        private async void StartAIConnection()
        {
            try
            {
                SynLog.Info("[Synaptic] Starting AI Connection...");

                // Start animation
                isConnecting = true;
                animationTime = 0f;
                Repaint();

                // Auto-setup if needed
                if (mcpSetupManager != null)
                {
                    var status = await mcpSetupManager.CheckSetupStatus();
                    if (!status.isMCPInstalled)
                    {
                        await mcpSetupManager.RunCompleteSetup();
                    }
                }

                // Start MCP server
                mcpServerRunning = await mcpSetupManager.StartMCPServer();

                // Stop animation
                isConnecting = false;

                if (mcpServerRunning)
                {
                    // Auto-generate configuration files for desktop AI
                    GenerateDesktopAIConfigs();

                    SynLog.Info("[Synaptic] ✅ AI connection setup complete! Desktop AI will auto-connect");
                    EditorUtility.DisplayDialog("AI Connection Ready", 
                        "Connection completed successfully.\n\n" +
                        "Unity tools are now available in AI apps.\n" +
                        "Type \"tools\" or \"unity\" to use the tools.", 
                        "OK");
                }
                else
                {
                    Debug.LogError("[Synaptic] ❌ Failed to start AI connection");

                    // Detailed guide when MCP server is not found
                    EditorUtility.DisplayDialog(
                        "MCP Server Not Found",
                        "Please launch Claude Desktop first to start AI connection.\n\n" +
                        "Steps:\n" +
                        "1. Launch Claude Desktop app\n" +
                        "2. Wait a moment, then press 'Start AI Connection' again\n\n" +
                        "Note: Unity acts as a client to the MCP server.",
                        "OK");
                }
                
                Repaint();
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] AI connection error: {e.Message}");
                isConnecting = false; // Stop animation
                mcpServerRunning = false;
                Repaint();
            }
        }
        
        private void StopAIConnection()
        {
            mcpServerRunning = false;
            SynLog.Info("[Synaptic] AI Connection stopped");
            Repaint();
        }
        
        private void ShowUsageGuide()
        {
            EditorUtility.DisplayDialog(
                "How to Use Unity MCP Tools",
                "Tips for reliable tool usage\n\n" +
                "1. Launch your AI tool:\n" +
                "   • Claude Desktop / Cursor / VS Code\n\n" +
                "2. Start a new chat\n\n" +
                "3. First, ask the AI:\n" +
                "   • \"What tools are available?\"\n" +
                "   • \"What can unity tools do?\"\n\n" +
                "4. Then, give specific instructions:\n" +
                "   • \"Use unity tools to create a red cube\"\n" +
                "   • \"Add a Player controller with tools\"\n\n" +
                "※ Including words like \"tools\" or \"unity\"\n" +
                "  helps the AI use tools more reliably!",
                "OK"
            );
        }
        
        private void ShowAIAppsDialog()
        {
            var option = EditorUtility.DisplayDialogComplex(
                "Select Desktop AI App",
                "Which AI app would you like to use?\n\n" +
                "ChatGPT: The world's most popular AI\n" +
                "Claude: AI with advanced code understanding\n\n" +
                "※ MCP-compatible version required",
                "ChatGPT",
                "Claude Desktop",
                "Cancel"
            );
            
            switch (option)
            {
                case 0: // ChatGPT
                    Application.OpenURL("https://chatgpt.com/");
                    break;
                case 1: // Claude
                    Application.OpenURL("https://claude.ai/download");
                    break;
            }
        }
        
        // Helper method to get appropriate server path based on selected AI client
        private string GetServerScriptPath()
        {
            var mcpServerPath = FindMCPServerPath();

            if (selectedAIClient == AIClientType.TokenSuperSaveMode)
            {
                // Token SuperSave mode: 3 meta-tools only
                return Path.Combine(mcpServerPath, "index-supersave.js");
            }
            else if (selectedAIClient == AIClientType.GitHubCopilot)
            {
                // Dynamic mode for GitHub Copilot (VS Code)
                return Path.Combine(mcpServerPath, "hub-server.js");
            }
            else if (selectedAIClient == AIClientType.CursorOrLMStudioEssential)
            {
                // Essential mode: 80 tools
                return Path.Combine(mcpServerPath, "index-essential.js");
            }
            else
            {
                // Full mode: 246 tools
                return Path.Combine(mcpServerPath, "index.js");
            }
        }

        // Update package.json "type" field based on selected server
        private void UpdatePackageJsonForSelectedServer()
        {
            try
            {
                var mcpServerPath = FindMCPServerPath();
                var packageJsonPath = Path.Combine(mcpServerPath, "package.json");

                if (!File.Exists(packageJsonPath))
                {
                    SynLog.Warn("[Synaptic] package.json not found. Skipping update.");
                    return;
                }

                // Read existing package.json
                var packageJsonContent = File.ReadAllText(packageJsonPath);
                var packageJson = JsonConvert.DeserializeObject<Dictionary<string, object>>(packageJsonContent);

                if (selectedAIClient == AIClientType.GitHubCopilot)
                {
                    // hub-server.js uses ESM (import) - requires "type": "module"
                    packageJson["type"] = "module";
                    packageJson["main"] = "hub-server.js";
                    SynLog.Info("[Synaptic] package.json updated for hub-server.js (ESM)");
                }
                else if (selectedAIClient == AIClientType.TokenSuperSaveMode)
                {
                    // index-supersave.js uses CommonJS (require) - remove "type" field
                    if (packageJson.ContainsKey("type"))
                    {
                        packageJson.Remove("type");
                    }
                    packageJson["main"] = "index-supersave.js";
                    SynLog.Info("[Synaptic] package.json updated for index-supersave.js (CommonJS)");
                }
                else
                {
                    // index.js uses CommonJS (require) - remove "type" field or set to "commonjs"
                    if (packageJson.ContainsKey("type"))
                    {
                        packageJson.Remove("type");
                    }
                    packageJson["main"] = "index.js";
                    SynLog.Info("[Synaptic] package.json updated for index.js (CommonJS)");
                }

                // Write updated package.json
                File.WriteAllText(packageJsonPath, JsonConvert.SerializeObject(packageJson, Newtonsoft.Json.Formatting.Indented));
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] Failed to update package.json: {e.Message}");
            }
        }

        private void GenerateDesktopAIConfigs()
        {
            try
            {
                var detectedAIs = DetectInstalledAIs();
                var configuredCount = 0;
                var configuredTools = new List<string>();

                foreach (var ai in detectedAIs)
                {
                    switch (ai.ToLower())
                    {
                        case "claude":
                            if (GenerateClaudeConfig())
                            {
                                configuredCount++;
                                configuredTools.Add("Claude Desktop");
                            }
                            break;
                        case "chatgpt":
                            if (GenerateChatGPTConfig())
                            {
                                configuredCount++;
                                configuredTools.Add("ChatGPT Desktop");
                            }
                            break;
                        case "gemini":
                            if (GenerateGeminiConfig())
                            {
                                configuredCount++;
                                configuredTools.Add("Gemini Desktop");
                            }
                            break;
                    }
                }

                // Always configure Cursor (user-level config)
                if (GenerateCursorConfig())
                {
                    configuredCount++;
                    configuredTools.Add("Cursor");
                }

                // Always configure VS Code (project-level config)
                if (GenerateVSCodeConfig())
                {
                    configuredCount++;
                    configuredTools.Add("VS Code");
                }

                // Always configure LM Studio (user-level config)
                if (GenerateLMStudioConfig())
                {
                    configuredCount++;
                    configuredTools.Add("LM Studio");
                }

                // Configure CLI tools (all in one setup)
                try
                {
                    if (GenerateClaudeCodeSpecificConfig())
                    {
                        configuredCount++;
                        configuredTools.Add("Claude Code");
                    }
                }
                catch { /* Ignore individual CLI errors */ }

                try
                {
                    GenerateWindsurfConfig();
                    configuredCount++;
                    configuredTools.Add("Windsurf");
                }
                catch { /* Ignore individual CLI errors */ }

                try
                {
                    if (GenerateAntigravityConfig())
                    {
                        configuredCount++;
                        configuredTools.Add("Google Antigravity");
                    }
                }
                catch { /* Ignore individual CLI errors */ }

                try
                {
                    if (GenerateKiroConfig())
                    {
                        configuredCount++;
                        configuredTools.Add("Amazon Kiro");
                    }
                }
                catch { /* Ignore individual CLI errors */ }

                // Update MCPServer/mcp-config.json with current project path
                UpdateMCPServerConfig();

                SynLog.Info($"[Synaptic] Auto-generated {configuredCount} MCP configurations: {string.Join(", ", configuredTools)}");
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] Configuration file generation error: {e.Message}");
            }
        }
        
        private List<string> DetectInstalledAIs()
        {
            var installedAIs = new List<string>();
            
            if (Application.platform == RuntimePlatform.OSXEditor)
            {
                // macOS application detection
                var appsDir = "/Applications";
                if (Directory.Exists($"{appsDir}/Claude.app")) installedAIs.Add("Claude");
                if (Directory.Exists($"{appsDir}/ChatGPT.app")) installedAIs.Add("ChatGPT");
                if (Directory.Exists($"{appsDir}/Gemini.app")) installedAIs.Add("Gemini");

                // Homebrew cask installation detection
                var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
                if (Directory.Exists($"{homeDir}/Applications/Claude.app")) installedAIs.Add("Claude");
                if (Directory.Exists($"{homeDir}/Applications/ChatGPT.app")) installedAIs.Add("ChatGPT");
            }
            else if (Application.platform == RuntimePlatform.WindowsEditor)
            {
                // Windows installation detection
                var programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
                var programFilesX86 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
                var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
                var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);

                // Claude: Check installation paths, config directory, AND Microsoft Store
                var hasClaude = Directory.Exists($"{programFiles}/Claude") ||
                    Directory.Exists($"{localAppData}/Programs/Claude") ||
                    Directory.Exists($"{appData}/Claude");

                // Also check for Microsoft Store version
                if (!hasClaude)
                {
                    var packagesDir = Path.Combine(localAppData, "Packages");
                    if (Directory.Exists(packagesDir))
                    {
                        try
                        {
                            var claudePackages = Directory.GetDirectories(packagesDir, "Claude_*");
                            if (claudePackages.Length == 0)
                            {
                                // Fallback: enumerate and filter
                                var allPackages = Directory.GetDirectories(packagesDir);
                                hasClaude = allPackages.Any(p =>
                                    Path.GetFileName(p).StartsWith("Claude", StringComparison.OrdinalIgnoreCase));
                            }
                            else
                            {
                                hasClaude = true;
                            }
                        }
                        catch { }
                    }
                }

                if (hasClaude)
                {
                    installedAIs.Add("Claude");
                }

                // ChatGPT
                if (Directory.Exists($"{programFiles}/ChatGPT") ||
                    Directory.Exists($"{localAppData}/ChatGPT") ||
                    Directory.Exists($"{appData}/ChatGPT"))
                {
                    installedAIs.Add("ChatGPT");
                }
            }
            
            return installedAIs.Distinct().ToList();
        }
        
        private bool GenerateClaudeConfig()
        {
            try
            {
                var claudeConfigDir = DetectClaudeConfigPath();
                if (string.IsNullOrEmpty(claudeConfigDir))
                {
                    SynLog.Warn("[Synaptic] Claude Desktop config path not detected.");
                    return false;
                }

            if (!Directory.Exists(claudeConfigDir))
            {
                Directory.CreateDirectory(claudeConfigDir);
            }

            var configPath = Path.Combine(claudeConfigDir, "claude_desktop_config.json");

            // Load existing configuration
            dynamic existingConfig = null;
            if (File.Exists(configPath))
            {
                try
                {
                    var existingJson = File.ReadAllText(configPath);
                    existingConfig = JsonConvert.DeserializeObject(existingJson);
                }
                catch (Exception e)
                {
                    SynLog.Warn($"[Synaptic] Failed to load existing Claude configuration: {e.Message}");
                }
            }

            // Unity MCP server configuration (v1.1.0: uses selected server script)
            // Normalize paths for cross-platform JSON compatibility (Windows: \ -> /)
            var unityMcpServer = new
            {
                command = FindNodePath(),
                args = new[] { NormalizePathForJson(GetServerScriptPath()) },
                cwd = NormalizePathForJson(FindMCPServerPath()),  // CRITICAL: Node.js needs to run from MCPServer directory
                env = new { }
            };

            // Merge with existing configuration
            dynamic claudeConfig;
            if (existingConfig?.mcpServers != null)
            {
                // Preserve existing mcpServers and add unity server
                var mcpServers = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                    JsonConvert.SerializeObject(existingConfig.mcpServers));
                mcpServers["unity-synaptic"] = unityMcpServer;

                claudeConfig = new
                {
                    mcpServers = mcpServers
                };

                // Preserve other existing settings
                var configDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                    JsonConvert.SerializeObject(existingConfig));
                configDict["mcpServers"] = mcpServers;
                claudeConfig = configDict;
            }
            else
            {
                // Create new configuration
                claudeConfig = new
                {
                    mcpServers = new Dictionary<string, object>
                    {
                        ["unity-synaptic"] = unityMcpServer
                    }
                };
            }
            
            File.WriteAllText(configPath, JsonConvert.SerializeObject(claudeConfig, Newtonsoft.Json.Formatting.Indented));

            SynLog.Info($"[Synaptic] Claude configuration file created: {configPath}");
            return true;
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] Claude configuration error: {e.Message}");
                return false;
            }
        }
        
        private string DetectClaudeConfigPath()
        {
            if (Application.platform == RuntimePlatform.OSXEditor)
            {
                // macOS Claude configuration path candidates
                var candidates = new[]
                {
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "Claude"),
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "com.anthropic.claudefordesktop"),
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "claude")
                };
                
                foreach (var path in candidates)
                {
                    var parentDir = Path.GetDirectoryName(path);
                    if (Directory.Exists(parentDir))
                    {
                        return path;
                    }
                }
            }
            else if (Application.platform == RuntimePlatform.WindowsEditor)
            {
                // Windows Claude configuration path candidates
                var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
                var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);

                // Find Microsoft Store package path dynamically
                string msStoreClaudePath = null;
                var packagesDir = Path.Combine(localAppData, "Packages");
                if (Directory.Exists(packagesDir))
                {
                    try
                    {
                        // Method 1: Direct pattern match
                        var claudePackages = Directory.GetDirectories(packagesDir, "Claude_*");

                        // Method 2: If pattern fails, enumerate and filter manually
                        if (claudePackages.Length == 0)
                        {
                            var allPackages = Directory.GetDirectories(packagesDir);
                            claudePackages = allPackages.Where(p =>
                                Path.GetFileName(p).StartsWith("Claude", StringComparison.OrdinalIgnoreCase)
                            ).ToArray();
                        }

                        if (claudePackages.Length > 0)
                        {
                            var candidatePath = Path.Combine(claudePackages[0], "LocalCache", "Roaming", "Claude");
                            // Verify the path actually exists or has config
                            if (Directory.Exists(candidatePath) ||
                                File.Exists(Path.Combine(candidatePath, "claude_desktop_config.json")))
                            {
                                msStoreClaudePath = candidatePath;
                            }
                            else
                            {
                                // Even if directory doesn't exist yet, use it if package is found
                                msStoreClaudePath = candidatePath;
                            }
                        }
                    }
                    catch { /* Ignore directory access errors */ }
                }

                var candidatesList = new List<string>
                {
                    Path.Combine(appData, "Claude"),                    // %APPDATA%\Claude (most common)
                    Path.Combine(localAppData, "Claude"),               // %LOCALAPPDATA%\Claude
                    Path.Combine(localAppData, "Programs", "Claude"),   // %LOCALAPPDATA%\Programs\Claude
                };

                // If Microsoft Store version is installed, ALWAYS use that path
                // (MS Store version only reads from its sandboxed location)
                if (!string.IsNullOrEmpty(msStoreClaudePath))
                {
                    return msStoreClaudePath;
                }

                var candidates = candidatesList.ToArray();

                // For standard installation, check if existing config file exists
                foreach (var path in candidates)
                {
                    var configFile = Path.Combine(path, "claude_desktop_config.json");
                    if (File.Exists(configFile))
                    {
                        return path;
                    }
                }

                // If no existing config, check if Claude directory exists
                foreach (var path in candidates)
                {
                    if (Directory.Exists(path))
                    {
                        return path;
                    }
                }

                // Default to standard %APPDATA%\Claude path (will create if needed)
                return Path.Combine(appData, "Claude");
            }

            return null;
        }

        private bool GenerateGeminiConfig()
        {
            try
            {
                var geminiConfigDir = DetectGeminiConfigPath();
                if (string.IsNullOrEmpty(geminiConfigDir))
                {
                    SynLog.Warn("[Synaptic] Gemini Desktop not found.");
                    return false;
                }

            if (!Directory.Exists(geminiConfigDir))
            {
                Directory.CreateDirectory(geminiConfigDir);
            }

            var geminiConfig = new
            {
                servers = new[]
                {
                    new
                    {
                        name = "unity-synaptic",
                        url = "http://localhost:3000",
                        type = "mcp"
                    }
                }
            };

            var configPath = Path.Combine(geminiConfigDir, "config.json");
            File.WriteAllText(configPath, JsonConvert.SerializeObject(geminiConfig, Newtonsoft.Json.Formatting.Indented));

            SynLog.Info($"[Synaptic] Gemini configuration file created: {configPath}");
            return true;
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] Gemini configuration error: {e.Message}");
                return false;
            }
        }
        
        private string DetectGeminiConfigPath()
        {
            if (Application.platform == RuntimePlatform.OSXEditor)
            {
                var candidates = new[]
                {
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "gemini"),
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "Gemini")
                };

                foreach (var path in candidates)
                {
                    var parentDir = Path.GetDirectoryName(path);
                    if (Directory.Exists(parentDir))
                    {
                        return path;
                    }
                }
            }
            else if (Application.platform == RuntimePlatform.WindowsEditor)
            {
                return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Gemini");
            }

            return null;
        }

        private string DetectCursorConfigPath()
        {
            // Cursor native MCP config: ~/.cursor/mcp.json
            var cursorDir = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
                ".cursor"
            );

            return cursorDir;
        }

        private bool GenerateCursorConfig()
        {
            try
            {
                var cursorConfigDir = DetectCursorConfigPath();
                if (string.IsNullOrEmpty(cursorConfigDir))
                {
                    SynLog.Warn("[Synaptic] Could not determine Cursor config path.");
                    return false;
                }

                if (!Directory.Exists(cursorConfigDir))
                {
                    Directory.CreateDirectory(cursorConfigDir);
                }

                var configPath = Path.Combine(cursorConfigDir, "mcp.json");

                // Load existing configuration
                dynamic existingConfig = null;
                if (File.Exists(configPath))
                {
                    try
                    {
                        var existingJson = File.ReadAllText(configPath);
                        existingConfig = JsonConvert.DeserializeObject(existingJson);
                    }
                    catch (Exception e)
                    {
                        SynLog.Warn($"[Synaptic] Failed to load existing Cursor configuration: {e.Message}");
                    }
                }

                // Unity MCP server configuration (v1.1.3: uses selected server script)
                // Normalize paths for cross-platform JSON compatibility (Windows: \ -> /)
                // Essential mode uses index-essential.js (80 tools), Full mode uses index.js (246 tools)
                var unityMcpServer = new
                {
                    command = FindNodePath(),
                    args = new[] { NormalizePathForJson(GetServerScriptPath()) },
                    cwd = NormalizePathForJson(FindMCPServerPath())  // CRITICAL: Node.js needs to run from MCPServer directory
                };

                // Merge with existing configuration
                dynamic cursorConfig;
                if (existingConfig?.mcpServers != null)
                {
                    var mcpServers = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(existingConfig.mcpServers));
                    mcpServers["unity-synaptic"] = unityMcpServer;

                    var configDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(existingConfig));
                    configDict["mcpServers"] = mcpServers;
                    cursorConfig = configDict;
                }
                else
                {
                    cursorConfig = new
                    {
                        mcpServers = new Dictionary<string, object>
                        {
                            ["unity-synaptic"] = unityMcpServer
                        }
                    };
                }

                File.WriteAllText(configPath, JsonConvert.SerializeObject(cursorConfig, Newtonsoft.Json.Formatting.Indented));

                SynLog.Info($"[Synaptic] ✅ Cursor configuration file created: {configPath}");
                return true;
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] Cursor configuration error: {e.Message}");
                return false;
            }
        }

        private string DetectVSCodeConfigPath()
        {
            // VS Code project-level MCP config: .vscode/mcp.json
            var projectPath = Application.dataPath.Replace("/Assets", "");
            var vscodeDir = Path.Combine(projectPath, ".vscode");

            return vscodeDir;
        }

        private bool GenerateVSCodeConfig()
        {
            try
            {
                var vscodeConfigDir = DetectVSCodeConfigPath();
                if (string.IsNullOrEmpty(vscodeConfigDir))
                {
                    SynLog.Warn("[Synaptic] Could not determine VS Code config path.");
                    return false;
                }

                if (!Directory.Exists(vscodeConfigDir))
                {
                    Directory.CreateDirectory(vscodeConfigDir);
                }

                var configPath = Path.Combine(vscodeConfigDir, "mcp.json");

                // Load existing configuration
                dynamic existingConfig = null;
                if (File.Exists(configPath))
                {
                    try
                    {
                        var existingJson = File.ReadAllText(configPath);
                        existingConfig = JsonConvert.DeserializeObject(existingJson);
                    }
                    catch (Exception e)
                    {
                        SynLog.Warn($"[Synaptic] Failed to load existing VS Code configuration: {e.Message}");
                    }
                }

                // Unity MCP server configuration (v1.1.0: VS Code format with "servers" and "type")
                // Normalize paths for cross-platform JSON compatibility (Windows: \ -> /)
                var unityMcpServer = new
                {
                    type = "stdio",  // Required by VS Code
                    command = FindNodePath(),
                    args = new[] { NormalizePathForJson(GetServerScriptPath()) },
                    cwd = NormalizePathForJson(FindMCPServerPath())  // CRITICAL: Node.js needs to run from MCPServer directory
                };

                // Merge with existing configuration (VS Code uses "servers", not "mcpServers")
                dynamic vscodeConfig;
                if (existingConfig?.servers != null)
                {
                    var servers = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(existingConfig.servers));
                    servers["unity-synaptic"] = unityMcpServer;

                    var configDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(existingConfig));
                    configDict["servers"] = servers;
                    vscodeConfig = configDict;
                }
                else
                {
                    vscodeConfig = new
                    {
                        servers = new Dictionary<string, object>
                        {
                            ["unity-synaptic"] = unityMcpServer
                        }
                    };
                }

                File.WriteAllText(configPath, JsonConvert.SerializeObject(vscodeConfig, Newtonsoft.Json.Formatting.Indented));

                SynLog.Info($"[Synaptic] ✅ VS Code configuration file created: {configPath}");
                return true;
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] VS Code configuration error: {e.Message}");
                return false;
            }
        }

        private string DetectLMStudioConfigPath()
        {
            var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);

            if (Application.platform == RuntimePlatform.OSXEditor)
            {
                // macOS: ~/.lmstudio/
                return Path.Combine(homeDir, ".lmstudio");
            }
            else if (Application.platform == RuntimePlatform.WindowsEditor)
            {
                // Windows: %USERPROFILE%/.lmstudio/
                return Path.Combine(homeDir, ".lmstudio");
            }

            return null;
        }

        private bool GenerateLMStudioConfig()
        {
            try
            {
                var lmstudioConfigDir = DetectLMStudioConfigPath();
                if (string.IsNullOrEmpty(lmstudioConfigDir))
                {
                    SynLog.Warn("[Synaptic] Could not determine LM Studio config path.");
                    return false;
                }

                if (!Directory.Exists(lmstudioConfigDir))
                {
                    Directory.CreateDirectory(lmstudioConfigDir);
                }

                var configPath = Path.Combine(lmstudioConfigDir, "mcp.json");

                // Load existing configuration
                dynamic existingConfig = null;
                if (File.Exists(configPath))
                {
                    try
                    {
                        var existingJson = File.ReadAllText(configPath);
                        existingConfig = JsonConvert.DeserializeObject(existingJson);
                    }
                    catch (Exception e)
                    {
                        SynLog.Warn($"[Synaptic] Failed to load existing LM Studio configuration: {e.Message}");
                    }
                }

                // Unity MCP server configuration (LM Studio uses same format as Cursor)
                // Normalize paths for cross-platform JSON compatibility (Windows: \ -> /)
                var unityMcpServer = new
                {
                    command = FindNodePath(),
                    args = new[] { NormalizePathForJson(GetServerScriptPath()) },
                    cwd = NormalizePathForJson(FindMCPServerPath()),  // CRITICAL: Node.js needs to run from MCPServer directory
                    env = new { }
                };

                // Merge with existing configuration
                dynamic lmstudioConfig;
                if (existingConfig?.mcpServers != null)
                {
                    var mcpServers = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(existingConfig.mcpServers));
                    mcpServers["unity-synaptic"] = unityMcpServer;

                    var configDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(existingConfig));
                    configDict["mcpServers"] = mcpServers;
                    lmstudioConfig = configDict;
                }
                else
                {
                    lmstudioConfig = new
                    {
                        mcpServers = new Dictionary<string, object>
                        {
                            ["unity-synaptic"] = unityMcpServer
                        }
                    };
                }

                File.WriteAllText(configPath, JsonConvert.SerializeObject(lmstudioConfig, Newtonsoft.Json.Formatting.Indented));

                SynLog.Info($"[Synaptic] ✅ LM Studio configuration file created: {configPath}");
                return true;
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] LM Studio configuration error: {e.Message}");
                return false;
            }
        }

        private bool UpdateMCPServerConfig()
        {
            try
            {
                var mcpServerPath = FindMCPServerPath();
                if (string.IsNullOrEmpty(mcpServerPath))
                {
                    SynLog.Warn("[Synaptic] MCP Server path not found.");
                    return false;
                }

                var configPath = Path.Combine(mcpServerPath, "mcp-config.json");
                if (!File.Exists(configPath))
                {
                    SynLog.Warn($"[Synaptic] mcp-config.json not found at: {configPath}");
                    return false;
                }

                // Read the config file
                var configContent = File.ReadAllText(configPath);

                // Replace placeholder with actual path
                configContent = configContent.Replace("{{PROJECT_MCP_SERVER_PATH}}", mcpServerPath);

                // Write back
                File.WriteAllText(configPath, configContent);

                SynLog.Info($"[Synaptic] ✅ Updated mcp-config.json with project path: {mcpServerPath}");
                return true;
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] mcp-config.json update error: {e.Message}");
                return false;
            }
        }

        private bool GenerateChatGPTConfig()
        {
            try
            {
                var chatgptConfigDir = DetectChatGPTConfigPath();
                if (string.IsNullOrEmpty(chatgptConfigDir))
                {
                    SynLog.Warn("[Synaptic] ChatGPT Desktop not found.");
                    return false;
                }

            if (!Directory.Exists(chatgptConfigDir))
            {
                Directory.CreateDirectory(chatgptConfigDir);
            }

            var configPath = Path.Combine(chatgptConfigDir, "config.json");

            // Load existing configuration
            dynamic existingConfig = null;
            if (File.Exists(configPath))
            {
                try
                {
                    var existingJson = File.ReadAllText(configPath);
                    existingConfig = JsonConvert.DeserializeObject(existingJson);
                }
                catch (Exception e)
                {
                    SynLog.Warn($"[Synaptic] Failed to load existing ChatGPT configuration: {e.Message}");
                }
            }

            // Unity MCP server configuration (v1.1.0: uses selected server script)
            // Normalize paths for cross-platform JSON compatibility (Windows: \ -> /)
            var unityMcpServer = new
            {
                command = FindNodePath(),
                args = new[] { NormalizePathForJson(GetServerScriptPath()) },
                env = new { }
            };

            // Merge with existing configuration
            dynamic chatgptConfig;
            if (existingConfig?.mcpServers != null)
            {
                // Preserve existing mcpServers and add unity server
                var mcpServers = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                    JsonConvert.SerializeObject(existingConfig.mcpServers));
                mcpServers["unity-synaptic"] = unityMcpServer;

                // Preserve other existing settings
                var configDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                    JsonConvert.SerializeObject(existingConfig));
                configDict["mcpServers"] = mcpServers;
                chatgptConfig = configDict;
            }
            else
            {
                // Create new configuration
                chatgptConfig = new
                {
                    mcpServers = new Dictionary<string, object>
                    {
                        ["unity-synaptic"] = unityMcpServer
                    }
                };
            }

            File.WriteAllText(configPath, JsonConvert.SerializeObject(chatgptConfig, Newtonsoft.Json.Formatting.Indented));

            SynLog.Info($"[Synaptic] ChatGPT configuration file created: {configPath}");
            return true;
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] ChatGPT configuration error: {e.Message}");
                return false;
            }
        }
        
        private string DetectChatGPTConfigPath()
        {
            if (Application.platform == RuntimePlatform.OSXEditor)
            {
                var candidates = new[]
                {
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "com.openai.chat"),
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support", "ChatGPT"),
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "chatgpt")
                };
                
                foreach (var path in candidates)
                {
                    var parentDir = Path.GetDirectoryName(path);
                    if (Directory.Exists(parentDir))
                    {
                        return path;
                    }
                }
            }
            else if (Application.platform == RuntimePlatform.WindowsEditor)
            {
                return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ChatGPT");
            }
            
            return null;
        }
        
        private async Task RefreshStatus()
        {
            mcpStatus = await mcpSetupManager.CheckSetupStatus();
            Repaint();
        }

        private void CheckMCPStatus()
        {
            // バックグラウンドスレッドで実行（Hold onを防ぐ）
            System.Threading.ThreadPool.QueueUserWorkItem(async _ =>
            {
                try
                {
                    mcpStatus = await mcpSetupManager.CheckSetupStatus();
                    EditorApplication.delayCall += () => { if (this) Repaint(); };
                }
                catch { }
            });
        }
        
        private void SaveMCPSettings()
        {
            // Save to .env file
            var envPath = Path.Combine(Application.dataPath.Replace("/Assets", ""), "MCPServer", ".env");
            var envContent = new List<string>
            {
                $"PORT={mcpPort}",
                $"WS_PORT={wsPort}"
            };

            System.IO.File.WriteAllLines(envPath, envContent);
            SynLog.Info("[Synaptic] MCP settings saved");
        }


        private async void StartMCPServer()
        {
            mcpServerRunning = await mcpSetupManager.StartMCPServer();
            Repaint();
        }

        private void StopMCPServer()
        {
            // Server stop implementation
            mcpServerRunning = false;
            Repaint();
        }
        
        private async void RestartMCPServer()
        {
            StopMCPServer();
            await Task.Delay(1000);
            await Task.Run(() => StartMCPServer());
        }
        
        private void ConfigureMCP()
        {
            try
            {
                SynLog.Info("[Synaptic] Starting MCP setup...");
                
                // Check and install dependencies
                if (!CheckAndInstallDependencies())
                {
                    EditorUtility.DisplayDialog(
                        "Setup Error",
                        "Failed to install required dependencies. Please check the console for details.",
                        "OK"
                    );
                    return;
                }
                
                // Generate MCP configuration files
                GenerateDesktopAIConfigs();

                // Update package.json based on selected server
                UpdatePackageJsonForSelectedServer();

                // Initialize MCP server
                if (mcpSetupManager == null)
                {
                    mcpSetupManager = NexusMCPSetupManager.Instance;
                }

                // Set configuration complete flag
                mcpConfigured = true;
                
                SynLog.Info("[Synaptic] MCP setup completed. Ready for AI integration.");

                // Display success message based on selected AI client (v1.1.0)
                string successMessage;
                if (selectedAIClient == AIClientType.GitHubCopilot)
                {
                    successMessage =
                        "MCP configuration completed for GitHub Copilot!\n\n" +
                        "Mode: Dynamic Tool Loading (hub-server.js)\n" +
                        "Configuration: .vscode/mcp.json\n\n" +
                        "⚠️ Important: Restart VS Code to activate Unity MCP.\n\n" +
                        "Initial tools: 8 management tools\n" +
                        "Dynamic loading: Use select_tools() to load more\n\n" +
                        "Example:\n" +
                        "\"Use select_tools to load GameObject and Material tools\"";
                }
                else
                {
                    successMessage =
                        "MCP configuration completed successfully!\n\n" +
                        "Mode: Full Mode (index.js) - All 246 tools\n" +
                        "Configurations created for:\n" +
                        "• Claude Desktop (claude_desktop_config.json)\n" +
                        "• Cursor (~/.cursor/mcp.json)\n" +
                        "• VS Code (.vscode/mcp.json)\n\n" +
                        "⚠️ Important: Restart/Reload your AI tool to activate Unity MCP.\n\n" +
                        "After restarting, ask:\n" +
                        "\"What Unity tools are available?\"";
                }

                EditorUtility.DisplayDialog(
                    "MCP Setup Complete",
                    successMessage,
                    "OK"
                );
                
                Repaint();
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] MCP configuration error: {e.Message}");
                EditorUtility.DisplayDialog(
                    "MCP Setup Error",
                    $"An error occurred during MCP setup:\n{e.Message}",
                    "OK"
                );
            }
        }
        
        private void ResetMCPConfiguration()
        {
            var confirmed = EditorUtility.DisplayDialog(
                "Reset MCP Settings",
                "Reset MCP settings and reconfigure?\n\n" +
                "Current AI connection will also be stopped.",
                "Reset",
                "Cancel"
            );
            
            if (confirmed)
            {
                // Reset configuration flag
                mcpConfigured = false;
                mcpSetupManager = null;

                SynLog.Info("[Synaptic] MCP settings have been reset. Please reconfigure.");

                EditorUtility.DisplayDialog(
                    "Settings Reset Complete",
                    "MCP settings have been reset.\n" +
                    "Please reconfigure from the 'Complete MCP Setup' button.",
                    "OK"
                );

                Repaint();
            }
        }
        
        // CLI AI configuration generation methods
        private void GenerateClaudeCodeConfig()
        {
            try
            {
                // Create Claude Code specific configuration (no detection required)
                if (GenerateClaudeCodeSpecificConfig())
                {
                    SynLog.Info("[Synaptic] Claude Code configuration complete");

                    EditorUtility.DisplayDialog(
                        "Claude Code Configuration Complete",
                        "Claude Code configuration has been completed.\n\n" +
                        "Configuration files:\n" +
                        "• Project: .claude/settings.local.json\n" +
                        "• Global: ~/.claude.json\n\n" +
                        "How to use:\n" +
                        "1. Restart Claude Code\n" +
                        "2. Unity MCP tools will be automatically enabled\n\n" +
                        "Verification commands:\n" +
                        "• claude mcp list\n" +
                        "• claude mcp get unity-synaptic",
                        "OK"
                    );
                }
                else
                {
                    EditorUtility.DisplayDialog("Error", "Failed to create Claude Code configuration. Please check Unity Console for errors.", "OK");
                }
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] Claude Code configuration error: {e.Message}");
                EditorUtility.DisplayDialog("Error", $"Claude Code configuration failed:\n{e.Message}", "OK");
            }
        }


        // DEPRECATED: CLI MCP configurations removed - HTTP API is the recommended approach
        // private void GenerateGeminiCLIConfig() { ... }
        // private void GenerateCodexCLIConfig() { ... }
        
        
        private void GenerateWindsurfConfig()
        {
            try
            {
                // Windsurf uses user-level config
                var windsurfConfigPath = Path.Combine(
                    Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
                    ".windsurf", "mcp_servers.json"
                );
                
                var windsurfDir = Path.GetDirectoryName(windsurfConfigPath);
                if (!Directory.Exists(windsurfDir))
                {
                    Directory.CreateDirectory(windsurfDir);
                }
                
                // Unity MCP server settings
                // Normalize paths for cross-platform JSON compatibility (Windows: \ -> /)
                var unityMcpServer = new
                {
                    command = FindNodePath(),
                    args = new[] { NormalizePathForJson(GetServerScriptPath()) },
                    env = new Dictionary<string, object>(),
                    description = "Unity game development tools"
                };

                // Load existing settings
                dynamic existingConfig = null;
                if (File.Exists(windsurfConfigPath))
                {
                    try
                    {
                        var existingJson = File.ReadAllText(windsurfConfigPath);
                        existingConfig = JsonConvert.DeserializeObject(existingJson);
                    }
                    catch (Exception e)
                    {
                        SynLog.Warn($"[Synaptic] Failed to load existing Windsurf config: {e.Message}");
                    }
                }
                
                // Windsurf MCP settings (2025 specification)
                dynamic windsurfConfig;
                if (existingConfig?.servers != null)
                {
                    var servers = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(existingConfig.servers));
                    servers["unity-synaptic"] = unityMcpServer;
                    
                    var configDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(existingConfig));
                    configDict["servers"] = servers;
                    windsurfConfig = configDict;
                }
                else
                {
                    windsurfConfig = new
                    {
                        servers = new Dictionary<string, object>
                        {
                            ["unity-synaptic"] = unityMcpServer
                        }
                    };
                }
                
                File.WriteAllText(windsurfConfigPath, JsonConvert.SerializeObject(windsurfConfig, Newtonsoft.Json.Formatting.Indented));
                
                SynLog.Info($"[Synaptic] Windsurf config file created: {windsurfConfigPath}");
                
                EditorUtility.DisplayDialog(
                    "Windsurf Configuration Complete",
                    "Windsurf MCP configuration created successfully.\n\n" +
                    "Config file: ~/.windsurf/mcp_servers.json\n\n" +
                    "Next steps:\n" +
                    "1. Restart Windsurf\n" +
                    "2. Unity MCP server will be available\n" +
                    "3. Use '@unity-synaptic' to access Unity tools\n\n" +
                    "The IDE that writes with you!",
                    "OK"
                );
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] Windsurf config error: {e.Message}");
                EditorUtility.DisplayDialog("Error", $"Failed to create Windsurf configuration:\n{e.Message}", "OK");
            }
        }

        private bool GenerateAntigravityConfig()
        {
            try
            {
                // Google Antigravity config path
                string configPath;
                if (Application.platform == RuntimePlatform.OSXEditor)
                {
                    // macOS: ~/.gemini/antigravity/mcp_config.json
                    configPath = Path.Combine(
                        Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
                        ".gemini", "antigravity", "mcp_config.json"
                    );
                }
                else if (Application.platform == RuntimePlatform.WindowsEditor)
                {
                    // Windows: %USERPROFILE%\.gemini\antigravity\mcp_config.json
                    configPath = Path.Combine(
                        Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
                        ".gemini", "antigravity", "mcp_config.json"
                    );
                }
                else
                {
                    SynLog.Warn("[Synaptic] Antigravity config: Unsupported platform");
                    return false;
                }

                var configDir = Path.GetDirectoryName(configPath);
                if (!Directory.Exists(configDir))
                {
                    Directory.CreateDirectory(configDir);
                }

                // Load existing configuration
                dynamic existingConfig = null;
                if (File.Exists(configPath))
                {
                    try
                    {
                        var existingJson = File.ReadAllText(configPath);
                        existingConfig = JsonConvert.DeserializeObject(existingJson);
                    }
                    catch (Exception e)
                    {
                        SynLog.Warn($"[Synaptic] Failed to load existing Antigravity config: {e.Message}");
                    }
                }

                // Unity MCP server configuration
                var unityMcpServer = new
                {
                    command = FindNodePath(),
                    args = new[] { NormalizePathForJson(GetServerScriptPath()) }
                };

                // Merge with existing configuration
                dynamic antigravityConfig;
                if (existingConfig?.mcpServers != null)
                {
                    var mcpServers = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(existingConfig.mcpServers));
                    mcpServers["unity-synaptic"] = unityMcpServer;

                    var configDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(existingConfig));
                    configDict["mcpServers"] = mcpServers;
                    antigravityConfig = configDict;
                }
                else
                {
                    antigravityConfig = new
                    {
                        mcpServers = new Dictionary<string, object>
                        {
                            ["unity-synaptic"] = unityMcpServer
                        }
                    };
                }

                File.WriteAllText(configPath, JsonConvert.SerializeObject(antigravityConfig, Newtonsoft.Json.Formatting.Indented));
                SynLog.Info($"[Synaptic] ✅ Google Antigravity config created: {configPath}");
                return true;
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] Antigravity config error: {e.Message}");
                return false;
            }
        }

        private bool GenerateKiroConfig()
        {
            try
            {
                // Amazon Kiro config path
                string configPath;
                if (Application.platform == RuntimePlatform.OSXEditor)
                {
                    // macOS: ~/.kiro/settings/mcp.json
                    configPath = Path.Combine(
                        Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
                        ".kiro", "settings", "mcp.json"
                    );
                }
                else if (Application.platform == RuntimePlatform.WindowsEditor)
                {
                    // Windows: %USERPROFILE%\.kiro\settings\mcp.json
                    configPath = Path.Combine(
                        Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
                        ".kiro", "settings", "mcp.json"
                    );
                }
                else
                {
                    SynLog.Warn("[Synaptic] Kiro config: Unsupported platform");
                    return false;
                }

                var configDir = Path.GetDirectoryName(configPath);
                if (!Directory.Exists(configDir))
                {
                    Directory.CreateDirectory(configDir);
                }

                // Load existing configuration
                dynamic existingConfig = null;
                if (File.Exists(configPath))
                {
                    try
                    {
                        var existingJson = File.ReadAllText(configPath);
                        existingConfig = JsonConvert.DeserializeObject(existingJson);
                    }
                    catch (Exception e)
                    {
                        SynLog.Warn($"[Synaptic] Failed to load existing Kiro config: {e.Message}");
                    }
                }

                // Unity MCP server configuration
                var unityMcpServer = new
                {
                    command = FindNodePath(),
                    args = new[] { NormalizePathForJson(GetServerScriptPath()) },
                    disabled = false
                };

                // Merge with existing configuration
                dynamic kiroConfig;
                if (existingConfig?.mcpServers != null)
                {
                    var mcpServers = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(existingConfig.mcpServers));
                    mcpServers["unity-synaptic"] = unityMcpServer;

                    var configDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(existingConfig));
                    configDict["mcpServers"] = mcpServers;
                    kiroConfig = configDict;
                }
                else
                {
                    kiroConfig = new
                    {
                        mcpServers = new Dictionary<string, object>
                        {
                            ["unity-synaptic"] = unityMcpServer
                        }
                    };
                }

                File.WriteAllText(configPath, JsonConvert.SerializeObject(kiroConfig, Newtonsoft.Json.Formatting.Indented));
                SynLog.Info($"[Synaptic] ✅ Amazon Kiro config created: {configPath}");
                return true;
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] Kiro config error: {e.Message}");
                return false;
            }
        }

        private void GenerateAllCLIConfigs()
        {
            try
            {
                SynLog.Info("[Synaptic] Configuring all MCP clients...");
                
                var configuredTools = new List<string>();
                
                // Claude Code
                try
                {
                    if (GenerateClaudeCodeSpecificConfig())
                    {
                        configuredTools.Add("Claude Code");
                    }
                }
                catch { /* Ignore individual CLI errors */ }
                
                // Cursor
                try
                {
                    if (GenerateCursorConfig())
                    {
                        configuredTools.Add("Cursor");
                    }
                }
                catch (Exception e)
                {
                    SynLog.Warn($"[Synaptic] Cursor config skipped: {e.Message}");
                }

                // VS Code
                try
                {
                    if (GenerateVSCodeConfig())
                    {
                        configuredTools.Add("VS Code");
                    }
                }
                catch (Exception e)
                {
                    SynLog.Warn($"[Synaptic] VS Code config skipped: {e.Message}");
                }

                // Windsurf
                try
                {
                    GenerateWindsurfConfig();
                    configuredTools.Add("Windsurf");
                }
                catch (Exception e)
                {
                    SynLog.Warn($"[Synaptic] Windsurf config skipped: {e.Message}");
                }

                // Google Antigravity
                try
                {
                    if (GenerateAntigravityConfig())
                    {
                        configuredTools.Add("Google Antigravity");
                    }
                }
                catch (Exception e)
                {
                    SynLog.Warn($"[Synaptic] Antigravity config skipped: {e.Message}");
                }

                // Amazon Kiro
                try
                {
                    if (GenerateKiroConfig())
                    {
                        configuredTools.Add("Amazon Kiro");
                    }
                }
                catch (Exception e)
                {
                    SynLog.Warn($"[Synaptic] Kiro config skipped: {e.Message}");
                }

                // Generic settings for other MCP-compatible tools
                GenerateUniversalCLIConfig();
                configuredTools.Add("Generic MCP Clients");
                
                SynLog.Info($"[Synaptic] All CLI AI configs completed: {string.Join(", ", configuredTools)}");
                
                EditorUtility.DisplayDialog(
                    "MCP Client Configuration Complete",
                    $"Successfully configured the following MCP clients:\n\n" +
                    $"✅ {string.Join("\n✅ ", configuredTools)}\n\n" +
                    "Unity MCP tools are now available in these applications.\n\n" +
                    "Next steps:\n" +
                    "1. Restart the configured applications\n" +
                    "2. Unity MCP tools will be automatically available\n" +
                    "3. Check each app's MCP panel or use '@unity-synaptic' mention",
                    "OK"
                );
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] All CLI AI config error: {e.Message}");
                EditorUtility.DisplayDialog("Error", $"Error during CLI AI configuration:\n{e.Message}", "OK");
            }
        }
        
        private void GenerateUniversalCLIConfig()
        {
            try
            {
                var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
                var configDir = Path.Combine(homeDir, ".config", "synaptic-pro");
                
                if (!Directory.Exists(configDir))
                {
                    Directory.CreateDirectory(configDir);
                }
                
                // Generic MCP config file
                // Normalize paths for cross-platform JSON compatibility (Windows: \ -> /)
                var universalConfig = new
                {
                    mcp_servers = new Dictionary<string, object>
                    {
                        ["unity-synaptic"] = new
                        {
                            command = FindNodePath(),
                            args = new[] { NormalizePathForJson(Path.Combine(FindMCPServerPath(), "index.js")) },
                            env = new { },
                            description = "Unity game development tools via MCP",
                            capabilities = new[] { "game_objects", "ui_creation", "scripting", "ai_agents", "animation" }
                        }
                    },
                    version = NexusVersion.Current,
                    created_by = "Synaptic Pro Unity Integration"
                };
                
                var configPath = Path.Combine(configDir, "mcp-config.json");
                File.WriteAllText(configPath, JsonConvert.SerializeObject(universalConfig, Newtonsoft.Json.Formatting.Indented));
                
                // Create usage example script
                var scriptPath = Path.Combine(configDir, "start-unity-mcp.sh");
                var scriptContent = $@"#!/bin/bash
# Unity MCP Server Starter Script
# Generated by Synaptic Pro Unity Integration

export MCP_CONFIG_PATH=""{NormalizePathForJson(configPath)}""
export UNITY_PROJECT_PATH=""{NormalizePathForJson(Application.dataPath.Replace($"{Path.DirectorySeparatorChar}Assets", ""))}""
export MCP_SERVER_PATH=""{NormalizePathForJson(FindMCPServerPath())}""

echo ""Starting Unity MCP Server...""
echo ""Project: $UNITY_PROJECT_PATH""
echo ""MCP Server: $MCP_SERVER_PATH""
echo ""Config: $MCP_CONFIG_PATH""

node ""$MCP_SERVER_PATH/index.js""
";
                
                File.WriteAllText(scriptPath, scriptContent);
                
                // Grant execute permission (Unix)
                if (Application.platform == RuntimePlatform.OSXEditor)
                {
                    System.Diagnostics.Process.Start("chmod", $"+x \"{scriptPath}\"");
                }
                
                SynLog.Info($"[Synaptic] Generic CLI config created: {configPath}");
            }
            catch (Exception e)
            {
                SynLog.Warn($"[Synaptic] Failed to create generic CLI config: {e.Message}");
            }
        }
        
        private void GenerateWatchConfig()
        {
            try
            {
                var projectPath = Application.dataPath.Replace("/Assets", "");
                var watchConfigPath = Path.Combine(projectPath, ".synaptic-watch");
                
                var watchConfig = new
                {
                    watch_patterns = new[]
                    {
                        "**/*.cs",
                        "**/*.js", 
                        "**/*.ts",
                        "**/*.json",
                        "**/*.md",
                        "**/*.yaml",
                        "**/*.yml"
                    },
                    ignore_patterns = new[]
                    {
                        "**/node_modules/**",
                        "**/Library/**",
                        "**/Temp/**",
                        "**/Logs/**",
                        "**/obj/**",
                        "**/bin/**"
                    },
                    commands = new
                    {
                        on_change = new[]
                        {
                            "echo \"File changed: {file}\"",
                            "# Add your custom commands here"
                        }
                    },
                    mcp_integration = new
                    {
                        enabled = true,
                        server_url = "ws://127.0.0.1:8090",
                        notify_on_change = true
                    }
                };
                
                File.WriteAllText(watchConfigPath, JsonConvert.SerializeObject(watchConfig, Newtonsoft.Json.Formatting.Indented));
                
                // Create watch script
                var watchScriptPath = Path.Combine(projectPath, "watch-synaptic.sh");
                var watchScript = $@"#!/bin/bash
# Synaptic File Watcher Script
# Monitors project files and notifies AI tools

if command -v fswatch >/dev/null 2>&1; then
    echo ""Starting Synaptic file watcher with fswatch...""
    fswatch -o . | while read f; do
        echo ""Files changed - notifying AI tools...""
        # Add notification logic here
    done
elif command -v inotifywait >/dev/null 2>&1; then
    echo ""Starting Synaptic file watcher with inotifywait...""
    inotifywait -m -r -e modify,create,delete . | while read path action file; do
        echo ""$path$file $action - notifying AI tools...""
        # Add notification logic here
    done
else
    echo ""Please install fswatch (macOS) or inotify-tools (Linux)""
    echo ""macOS: brew install fswatch""
    echo ""Linux: sudo apt-get install inotify-tools""
fi
";
                
                File.WriteAllText(watchScriptPath, watchScript);
                
                // Grant execute permission
                if (Application.platform == RuntimePlatform.OSXEditor)
                {
                    System.Diagnostics.Process.Start("chmod", $"+x \"{watchScriptPath}\"");
                }
                
                SynLog.Info($"[Synaptic] Watch config creation completed: {watchConfigPath}");

                EditorUtility.DisplayDialog(
                    "Watch Config Created",
                    $"File monitoring configuration created:\n\n" +
                    $"Config file: .synaptic-watch\n" +
                    $"Script: watch-synaptic.sh\n\n" +
                    "Monitored:\n" +
                    "• C#, JavaScript, TypeScript\n" +
                    "• JSON, Markdown, YAML\n\n" +
                    "Usage: ./watch-synaptic.sh",
                    "OK"
                );
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] Watch config error: {e.Message}");
                EditorUtility.DisplayDialog("Error", $"Failed to create Watch config:\n{e.Message}", "OK");
            }
        }
        
        // CLI detection and config path detection methods
        private string CheckCLIInstallation(string cliName)
        {
            try
            {
                // Try normal which command
                var startInfo = new System.Diagnostics.ProcessStartInfo
                {
                    FileName = "which",
                    Arguments = cliName,
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    CreateNoWindow = true
                };
                
                using (var process = System.Diagnostics.Process.Start(startInfo))
                {
                    var output = process.StandardOutput.ReadToEnd().Trim();
                    process.WaitForExit();
                    
                    if (process.ExitCode == 0 && !string.IsNullOrEmpty(output))
                    {
                        return output;
                    }
                }
                
                // CLI-specific path detection
                return CheckCLISpecificPaths(cliName);
            }
            catch (Exception e)
            {
                SynLog.Warn($"[Synaptic] CLI check error ({cliName}): {e.Message}");
            }
            
            return null;
        }
        
        private string CheckCLISpecificPaths(string cliName)
        {
            switch (cliName)
            {
                case "claude-code":
                    return CheckClaudeCodePaths();
                    
                    
                case "gemini":
                    return CheckGeminiCLIPaths();
                    
                case "codex":
                    return CheckCodexCLIPaths();
                    
                default:
                    return null;
            }
        }
        
        private string CheckClaudeCodePaths()
        {
            var paths = new[]
            {
                // Homebrew (Apple Silicon)
                "/opt/homebrew/Caskroom/claude-code/*/claude",
                "/opt/homebrew/bin/claude-code",
                
                // Homebrew (Intel)
                "/usr/local/Caskroom/claude-code/*/claude",
                "/usr/local/bin/claude-code",
                
                // NPM global
                "/usr/local/lib/node_modules/@anthropic/claude-code/bin/claude-code",
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.npm-global/bin/claude-code",
                
                // Standalone installers
                "/Applications/Claude Code.app/Contents/MacOS/Claude Code",
                "/Applications/Claude.app/Contents/MacOS/Claude",
                
                // Direct download installs
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/Applications/Claude Code.app/Contents/MacOS/Claude Code",
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/Downloads/claude-code",
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/bin/claude-code",
                
                // pnpm/yarn global
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.local/share/pnpm/claude-code",
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.yarn/bin/claude-code"
            };
            
            return FindExecutableInPaths(paths, "claude");
        }
        
        
        private string CheckGeminiCLIPaths()
        {
            var paths = new[]
            {
                // Google Cloud SDK
                "/usr/local/bin/gcloud",
                "/opt/homebrew/bin/gcloud",
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/google-cloud-sdk/bin/gcloud",
                
                // Gemini specific CLI
                "/usr/local/bin/gemini",
                "/opt/homebrew/bin/gemini",
                
                // NPM installs
                "/usr/local/lib/node_modules/@google/gemini-cli/bin/gemini",
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.npm-global/bin/gemini",
                
                // pip installs
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.local/bin/gemini",
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.local/bin/google-generativeai",
                
                // conda
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/anaconda3/bin/gemini",
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/miniconda3/bin/gemini",
                
                // Direct installs
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/bin/gemini",
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/Downloads/gemini",
                
                // Snap (if on Linux)
                "/snap/bin/gemini",
                
                // pnpm/yarn
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.local/share/pnpm/gemini",
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.yarn/bin/gemini"
            };
            
            return FindExecutableInPaths(paths, "gemini");
        }
        
        private string CheckCodexCLIPaths()
        {
            var paths = new[]
            {
                // NPM global installs
                "/usr/local/bin/codex",
                "/opt/homebrew/bin/codex",
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.npm-global/bin/codex",
                
                // OpenAI official CLI
                "/usr/local/lib/node_modules/@openai/codex/bin/codex",
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.npm-global/lib/node_modules/@openai/codex/bin/codex",
                
                // pnpm/yarn global
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.local/share/pnpm/codex",
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.yarn/bin/codex",
                
                // Direct installs
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/bin/codex",
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/Downloads/codex",
                
                // Homebrew
                "/opt/homebrew/bin/openai-codex",
                "/usr/local/bin/openai-codex",
                
                // Rust cargo install
                Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/.cargo/bin/codex",
                
                // Alternative names
                "/usr/local/bin/openai-codex-cli",
                "/opt/homebrew/bin/openai-codex-cli"
            };
            
            return FindExecutableInPaths(paths, "codex");
        }
        
        private string FindExecutableInPaths(string[] paths, string fallbackName)
        {
            foreach (var path in paths)
            {
                try
                {
                    if (path.Contains("*"))
                    {
                        // Path with wildcards
                        var baseDir = Path.GetDirectoryName(path);
                        var fileName = Path.GetFileName(path);
                        
                        if (Directory.Exists(baseDir))
                        {
                            var subdirs = Directory.GetDirectories(baseDir);
                            foreach (var subdir in subdirs)
                            {
                                var fullPath = Path.Combine(subdir, fileName);
                                if (File.Exists(fullPath))
                                {
                                    return fullPath;
                                }
                            }
                        }
                    }
                    else if (File.Exists(path))
                    {
                        return path;
                    }
                }
                catch (Exception e)
                {
                    SynLog.Warn($"[Synaptic] Path check error ({path}): {e.Message}");
                }
            }
            
            // Detect from running processes
            return FindInRunningProcesses(fallbackName);
        }
        
        private string FindInRunningProcesses(string processName)
        {
            try
            {
                var psStartInfo = new System.Diagnostics.ProcessStartInfo
                {
                    FileName = "ps",
                    Arguments = "aux",
                    UseShellExecute = false,
                    RedirectStandardOutput = true,
                    CreateNoWindow = true
                };
                
                using (var psProcess = System.Diagnostics.Process.Start(psStartInfo))
                {
                    var psOutput = psProcess.StandardOutput.ReadToEnd();
                    psProcess.WaitForExit();
                    
                    var lines = psOutput.Split('\n');
                    foreach (var line in lines)
                    {
                        // More strict process name matching
                        if (IsProcessLineMatch(line, processName))
                        {
                            var parts = line.Split(' ', StringSplitOptions.RemoveEmptyEntries);
                            if (parts.Length > 10)
                            {
                                var executablePath = parts[10];
                                if (File.Exists(executablePath) && IsCorrectExecutable(executablePath, processName))
                                {
                                    return executablePath;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                SynLog.Warn($"[Synaptic] Process detection error ({processName}): {e.Message}");
            }
            
            return null;
        }
        
        private bool IsProcessLineMatch(string line, string processName)
        {
            switch (processName.ToLower())
            {
                case "claude":
                    // For Claude Code: claude-code or claude, but exclude gemini etc
                    return (line.Contains("claude-code") || line.Contains("/claude")) && 
                           !line.Contains("gemini") && !line.Contains("codex");
                           
                    
                case "gemini":
                    // For Gemini
                    return line.Contains("gemini") && !line.Contains("claude") && !line.Contains("codex");
                    
                case "codex":
                    // For Codex
                    return line.Contains("codex") && !line.Contains("claude") && !line.Contains("gemini");
                    
                default:
                    return line.Contains(processName);
            }
        }
        
        private bool IsCorrectExecutable(string executablePath, string processName)
        {
            var fileName = Path.GetFileNameWithoutExtension(executablePath).ToLower();
            var fullPath = executablePath.ToLower();
            
            switch (processName.ToLower())
            {
                case "claude":
                    // For Claude Code - distinguish from Claude Desktop
                    if (fullPath.Contains("claude-code") || fullPath.Contains("caskroom/claude-code"))
                    {
                        return true; // Clearly Claude Code path
                    }
                    
                    // Exclude Claude Desktop
                    if (fullPath.Contains("/applications/claude.app") || fullPath.Contains("claude.app/contents"))
                    {
                        return false; // Exclude because it's Claude Desktop
                    }
                    
                    return (fileName == "claude-code") && !fullPath.Contains("gemini") && !fullPath.Contains("codex");
                           
                           
                case "gemini":
                    return (fileName.Contains("gemini") || fileName == "gemini" || fileName == "gcloud") && 
                           (fullPath.Contains("gemini") || fullPath.Contains("google")) && 
                           !fullPath.Contains("claude") && !fullPath.Contains("codex");
                           
                case "codex":
                    return (fileName.Contains("codex") || fileName == "codex" || fileName == "openai-codex") && 
                           fullPath.Contains("codex") && 
                           !fullPath.Contains("claude") && !fullPath.Contains("chatgpt") && !fullPath.Contains("gemini");
                           
                default:
                    return fileName == processName.ToLower() || fileName.Contains(processName.ToLower());
            }
        }
        
        
        private string DetectGeminiCLIConfigPath()
        {
            try
            {
                var candidates = new[]
                {
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "gemini", "config.json"),
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".gemini", "config.json"),
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".google", "gemini", "config.json")
                };
                
                foreach (var path in candidates)
                {
                    var dir = Path.GetDirectoryName(path);
                    if (Directory.Exists(dir) || path.Contains("gemini"))
                    {
                        return path;
                    }
                }
            }
            catch (Exception e)
            {
                SynLog.Warn($"[Synaptic] Gemini CLI config path detection error: {e.Message}");
            }
            
            return null;
        }
        
        private string DetectCodexCLIConfigPath()
        {
            try
            {
                var candidates = new[]
                {
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "openai", "codex.json"),
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config", "codex", "config.json"),
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".codex", "config.json"),
                    Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".openai", "codex.json")
                };
                
                foreach (var path in candidates)
                {
                    var dir = Path.GetDirectoryName(path);
                    if (Directory.Exists(dir) || path.Contains("openai") || path.Contains("codex"))
                    {
                        return path;
                    }
                }
            }
            catch (Exception e)
            {
                SynLog.Warn($"[Synaptic] OpenAI Codex CLI config path detection error: {e.Message}");
            }
            
            return null;
        }
        
        private bool GenerateClaudeCodeSpecificConfig()
        {
            try
            {
                var projectPath = Application.dataPath.Replace("/Assets", "");
                var claudeDir = Path.Combine(projectPath, ".claude");
                var claudeConfigPath = Path.Combine(claudeDir, "settings.local.json");
                
                // Load existing settings
                dynamic existingConfig = null;
                if (File.Exists(claudeConfigPath))
                {
                    try
                    {
                        var existingJson = File.ReadAllText(claudeConfigPath);
                        existingConfig = JsonConvert.DeserializeObject(existingJson);
                    }
                    catch (Exception e)
                    {
                        SynLog.Warn($"[Synaptic] Failed to load existing Claude Code config: {e.Message}");
                    }
                }
                
                // Unity MCP server settings (2025 specification)
                // Normalize paths for cross-platform JSON compatibility (Windows: \ -> /)
                var unityMcpServer = new
                {
                    command = FindNodePath(),
                    args = new[] { NormalizePathForJson(GetServerScriptPath()) },
                    env = new Dictionary<string, object>()
                };

                // Create .claude directory
                if (!Directory.Exists(claudeDir))
                {
                    Directory.CreateDirectory(claudeDir);
                }
                
                // Project-specific config structure (2025 Claude Code format)
                dynamic claudeCodeConfig;
                if (existingConfig?.mcpServers != null)
                {
                    // Get existing mcpServers
                    var mcpServers = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(existingConfig.mcpServers));
                    mcpServers["unity-synaptic"] = unityMcpServer;
                    
                    // Update entire config
                    var configDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(existingConfig));
                    configDict["mcpServers"] = mcpServers;
                    claudeCodeConfig = configDict;
                }
                else
                {
                    // Create new - 2025 MCP specification compliant
                    claudeCodeConfig = new
                    {
                        mcpServers = new Dictionary<string, object>
                        {
                            ["unity-synaptic"] = unityMcpServer
                        },
                        permissions = new
                        {
                            allow = new[] { "mcp__unity-synaptic" },
                            deny = new object[] { }
                        }
                    };
                }
                
                File.WriteAllText(claudeConfigPath, JsonConvert.SerializeObject(claudeCodeConfig, Newtonsoft.Json.Formatting.Indented));
                
                SynLog.Info($"[Synaptic] Claude Code config file created: {claudeConfigPath}");
                
                // Also create alternate config path (user global settings)
                var userConfigPath = Path.Combine(
                    Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
                    ".claude.json"
                );
                
                CreateUserLevelConfig(userConfigPath, unityMcpServer);
                
                return true;
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] Claude Code specific config error: {e.Message}");
                return false;
            }
        }
        
        private void CreateUserLevelConfig(string userConfigPath, object unityMcpServer)
        {
            try
            {
                dynamic userConfig = null;
                
                // Load existing user-level settings
                if (File.Exists(userConfigPath))
                {
                    try
                    {
                        var existingJson = File.ReadAllText(userConfigPath);
                        userConfig = JsonConvert.DeserializeObject(existingJson);
                    }
                    catch (Exception e)
                    {
                        SynLog.Warn($"[Synaptic] Failed to load existing user settings: {e.Message}");
                    }
                }
                
                // Update or create user-level settings
                if (userConfig?.mcpServers != null)
                {
                    var mcpServers = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(userConfig.mcpServers));
                    mcpServers["unity-synaptic"] = unityMcpServer;
                    
                    var configDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(
                        JsonConvert.SerializeObject(userConfig));
                    configDict["mcpServers"] = mcpServers;
                    userConfig = configDict;
                }
                else
                {
                    userConfig = new
                    {
                        mcpServers = new Dictionary<string, object>
                        {
                            ["unity-synaptic"] = unityMcpServer
                        }
                    };
                }
                
                File.WriteAllText(userConfigPath, JsonConvert.SerializeObject(userConfig, Newtonsoft.Json.Formatting.Indented));
                SynLog.Info($"[Synaptic] User global settings also created: {userConfigPath}");
            }
            catch (Exception e)
            {
                SynLog.Warn($"[Synaptic] User global settings creation skipped: {e.Message}");
            }
        }
        
        /// <summary>
        /// Normalize file path for JSON/Node.js consumption.
        /// Converts Windows backslashes to forward slashes.
        /// Node.js handles both, but forward slashes work cross-platform in JSON.
        /// </summary>
        private string NormalizePathForJson(string path)
        {
            if (string.IsNullOrEmpty(path))
                return path;

            // Convert backslashes to forward slashes for cross-platform JSON compatibility
            return path.Replace("\\", "/");
        }

        private static string _cachedMCPServerPath = null;

        private string FindMCPServerPath()
        {
            // キャッシュがあればそのまま返す（毎回の再帰検索を防ぐ）
            if (!string.IsNullOrEmpty(_cachedMCPServerPath) && Directory.Exists(_cachedMCPServerPath))
            {
                return _cachedMCPServerPath;
            }

            // 1. まず既知のパスを直接チェック（高速）
            var knownPath = Path.Combine(Application.dataPath, "Synaptic AI Pro", "MCPServer");
            if (Directory.Exists(knownPath))
            {
                SynLog.Info($"[Synaptic] Found MCPServer at known path: {knownPath}");
                _cachedMCPServerPath = knownPath;
                return knownPath;
            }

            // 2. Assets直下のみ検索（AllDirectoriesではなくTopDirectoryOnly + 1階層）
            try
            {
                foreach (var dir in Directory.GetDirectories(Application.dataPath, "*", SearchOption.TopDirectoryOnly))
                {
                    var mcpPath = Path.Combine(dir, "MCPServer");
                    if (Directory.Exists(mcpPath))
                    {
                        SynLog.Info($"[Synaptic] Found MCPServer in Assets: {mcpPath}");
                        _cachedMCPServerPath = mcpPath;
                        return mcpPath;
                    }
                }
            }
            catch { }

            // 3. Packages（パッケージマネージャー経由）
            string projectPath = Application.dataPath.Replace($"{Path.DirectorySeparatorChar}Assets", "");
            string packagesPath = Path.Combine(projectPath, "Packages");
            if (Directory.Exists(packagesPath))
            {
                try
                {
                    foreach (var dir in Directory.GetDirectories(packagesPath, "*", SearchOption.TopDirectoryOnly))
                    {
                        var mcpPath = Path.Combine(dir, "MCPServer");
                        if (Directory.Exists(mcpPath))
                        {
                            SynLog.Info($"[Synaptic] Found MCPServer in Packages: {mcpPath}");
                            _cachedMCPServerPath = mcpPath;
                            return mcpPath;
                        }
                    }
                }
                catch { }
            }

            // 4. Library/PackageCache（UPMキャッシュ）- synapticパッケージのみ検索
            string packageCachePath = Path.Combine(projectPath, "Library", "PackageCache");
            if (Directory.Exists(packageCachePath))
            {
                try
                {
                    foreach (var dir in Directory.GetDirectories(packageCachePath, "com.synaptic*", SearchOption.TopDirectoryOnly))
                    {
                        var mcpPath = Path.Combine(dir, "MCPServer");
                        if (Directory.Exists(mcpPath))
                        {
                            SynLog.Info($"[Synaptic] Found MCPServer in PackageCache: {mcpPath}");
                            _cachedMCPServerPath = mcpPath;
                            return mcpPath;
                        }
                    }
                }
                catch { }
            }

            // 5. フォールバック
            string defaultPath = Path.Combine(Application.dataPath, "Synaptic AI Pro", "MCPServer");
            SynLog.Warn($"[Synaptic] MCPServer not found, using default path: {defaultPath}");
            _cachedMCPServerPath = defaultPath;
            return defaultPath;
        }

        /// <summary>
        // ===== Auto-Update System =====

        private static string PREF_LAST_UPDATE_CHECK => "SynapticPro_LastUpdateCheck";

        private void CheckForUpdates()
        {
            if (updateCheckDone) return;

            // 1日1回チェック
            var lastCheck = EditorPrefs.GetString(PREF_LAST_UPDATE_CHECK, "");
            var today = DateTime.Now.ToString("yyyy-MM-dd");
            if (lastCheck == today) return;

            updateCheckDone = true;
            EditorPrefs.SetString(PREF_LAST_UPDATE_CHECK, today);

            var currentVersion = NexusVersion.Current;
            var dist = ENABLE_SELF_UPDATE ? "booth" : "assetstore";

            System.Threading.ThreadPool.QueueUserWorkItem(_ =>
            {
                try
                {
                    using (var client = new System.Net.WebClient())
                    {
                        client.Headers.Add("User-Agent", "SynapticAIPro-Unity");
                        var url = $"https://kawaii-agent-backend.vercel.app/api/synaptic/unity-version?v={currentVersion}&dist={dist}";
                        var json = client.DownloadString(url);

                        // Simple JSON parsing
                        if (json.Contains("\"updateAvailable\":true") || json.Contains("\"updateAvailable\": true"))
                        {
                            // Extract latestVersion
                            var vMatch = System.Text.RegularExpressions.Regex.Match(json, "\"latestVersion\"\\s*:\\s*\"([^\"]+)\"");
                            var urlMatch = System.Text.RegularExpressions.Regex.Match(json, "\"updateUrl\"\\s*:\\s*\"([^\"]+)\"");
                            var methodMatch = System.Text.RegularExpressions.Regex.Match(json, "\"updateMethod\"\\s*:\\s*\"([^\"]+)\"");

                            if (vMatch.Success)
                            {
                                latestVersion = vMatch.Groups[1].Value;
                                updateUrl = urlMatch.Success ? urlMatch.Groups[1].Value : "";
                                updateMethod = methodMatch.Success ? methodMatch.Groups[1].Value : "browser";
                                updateAvailable = true;

                                EditorApplication.delayCall += () =>
                                {
                                    SynLog.Info($"[Synaptic] Update available: {currentVersion} → {latestVersion}");
                                    Repaint();
                                };
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    // フェイルサイレント
                    SynLog.Info($"[Synaptic] Update check failed (non-critical): {e.Message}");
                }
            });
        }

        private void DrawUpdateBanner()
        {
            if (!updateAvailable) return;

            EditorGUILayout.BeginHorizontal(EditorStyles.helpBox);

            var oldColor = GUI.backgroundColor;
            GUI.backgroundColor = new Color(0.2f, 0.6f, 1f);

            EditorGUILayout.LabelField(
                $"🔄 v{latestVersion} available (current: {NexusVersion.Current})",
                EditorStyles.boldLabel,
                GUILayout.ExpandWidth(true)
            );

            if (updateMethod == "auto" && ENABLE_SELF_UPDATE)
            {
                if (GUILayout.Button("Update Now", GUILayout.Width(100), GUILayout.Height(22)))
                {
                    StartAutoUpdate();
                }
            }
            else
            {
                if (GUILayout.Button("Open Store", GUILayout.Width(100), GUILayout.Height(22)))
                {
                    Application.OpenURL(updateUrl);
                }
            }

            GUI.backgroundColor = oldColor;
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.Space(5);
        }

        private async void StartAutoUpdate()
        {
            if (isDownloadingUpdate) return;
            isDownloadingUpdate = true;

            try
            {
                SynLog.Info($"[Synaptic] Downloading update v{latestVersion}...");

                // ダウンロード先
                var downloadPath = Path.Combine(Path.GetTempPath(), $"SynapticAIPro_v{latestVersion}.unitypackage.zip");

                await Task.Run(() =>
                {
                    using (var client = new System.Net.WebClient())
                    {
                        client.Headers.Add("User-Agent", "SynapticAIPro-Unity");
                        client.DownloadFile(updateUrl, downloadPath);
                    }
                });

                SynLog.Info($"[Synaptic] Downloaded to: {downloadPath}");

                // ZIPを展開してunitypackageを取得
                var extractDir = Path.Combine(Path.GetTempPath(), "SynapticUpdate");
                if (Directory.Exists(extractDir)) Directory.Delete(extractDir, true);

                // System.IO.Compression でZIP展開
                System.IO.Compression.ZipFile.ExtractToDirectory(downloadPath, extractDir);

                // .unitypackageファイルを探す
                var packages = Directory.GetFiles(extractDir, "*.unitypackage", SearchOption.AllDirectories);
                if (packages.Length > 0)
                {
                    var packagePath = packages[0];
                    SynLog.Info($"[Synaptic] Importing update package: {packagePath}");

                    var synapticPath = Path.Combine(Application.dataPath, "Synaptic AI Pro");

                    // ===== セーフガード =====
                    // 1. unitypackageファイルサイズ妥当性チェック
                    var pkgInfo = new FileInfo(packagePath);
                    if (pkgInfo.Length < 100_000) // < 100KB
                    {
                        EditorUtility.DisplayDialog("Update Failed",
                            "ダウンロードしたファイルが破損している可能性があります。手動で再ダウンロードしてください。",
                            "OK");
                        return;
                    }

                    // 2. パス妥当性チェック - 正確に "Synaptic AI Pro" フォルダのみ操作
                    var fullPath = Path.GetFullPath(synapticPath);
                    var assetsFullPath = Path.GetFullPath(Application.dataPath);

                    // パスが Assets/Synaptic AI Pro として整合してるか厳密確認
                    if (!fullPath.StartsWith(assetsFullPath, System.StringComparison.OrdinalIgnoreCase) ||
                        !fullPath.EndsWith("Synaptic AI Pro", System.StringComparison.OrdinalIgnoreCase) ||
                        fullPath.Equals(assetsFullPath, System.StringComparison.OrdinalIgnoreCase))
                    {
                        EditorUtility.DisplayDialog("Update Failed",
                            "アップデート対象フォルダの検証に失敗しました。\n手動で再インストールしてください。",
                            "OK");
                        return;
                    }

                    // 3. 既存フォルダが Synaptic AI Pro として整合してるか確認 (Editor配下に既知ファイルがある)
                    if (Directory.Exists(synapticPath))
                    {
                        var marker = Path.Combine(synapticPath, "Editor", "NexusSetupWindow.cs");
                        if (!File.Exists(marker))
                        {
                            EditorUtility.DisplayDialog("Update Failed",
                                "アップデート対象フォルダが Synaptic AI Pro のインストール先として認識できません。\n別のフォルダにインストールされている可能性があります。手動で再インストールしてください。",
                                "OK");
                            return;
                        }

                        Directory.Delete(synapticPath, true);
                        // .metaも削除
                        var metaPath = synapticPath + ".meta";
                        if (File.Exists(metaPath)) File.Delete(metaPath);
                    }

                    // インポート
                    AssetDatabase.ImportPackage(packagePath, false); // false = 確認ダイアログなし
                    AssetDatabase.Refresh();

                    updateAvailable = false;
                    SynLog.Info($"[Synaptic] Update to v{latestVersion} complete!");
                    EditorUtility.DisplayDialog("Update Complete",
                        $"Synaptic AI Pro has been updated to v{latestVersion}.\nPlease restart Unity for changes to take effect.",
                        "OK");
                }
                else
                {
                    Debug.LogError("[Synaptic] No .unitypackage found in downloaded ZIP");
                }

                // クリーンアップ
                try { File.Delete(downloadPath); } catch { }
                try { Directory.Delete(extractDir, true); } catch { }
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] Auto-update failed: {e.Message}");
                EditorUtility.DisplayDialog("Update Failed",
                    $"Auto-update failed: {e.Message}\n\nPlease download manually from BOOTH.",
                    "OK");
            }
            finally
            {
                isDownloadingUpdate = false;
            }
        }

        /// <summary>
        /// Find Node.js executable path across different OS and installation locations
        /// Supports Windows D: drive installations, nvm, volta, and standard locations
        /// </summary>
        private string FindNodePath()
        {
            string nodeExecutable = Application.platform == RuntimePlatform.WindowsEditor ? "node.exe" : "node";

            // 1. Check PATH environment variable first
            var pathEnv = Environment.GetEnvironmentVariable("PATH");
            if (!string.IsNullOrEmpty(pathEnv))
            {
                var separator = Application.platform == RuntimePlatform.WindowsEditor ? ';' : ':';
                foreach (var path in pathEnv.Split(separator))
                {
                    if (!string.IsNullOrEmpty(path))
                    {
                        var fullPath = Path.Combine(path.Trim(), nodeExecutable);
                        if (File.Exists(fullPath))
                        {
                            SynLog.Info($"[Synaptic] Found Node.js in PATH: {fullPath}");
                            return NormalizePathForJson(fullPath);
                        }
                    }
                }
            }

            // 2. Check common installation paths
            var searchPaths = new List<string>();

            if (Application.platform == RuntimePlatform.WindowsEditor)
            {
                // Windows standard locations
                var programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
                var programFilesX86 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
                var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
                var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
                var userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);

                searchPaths.AddRange(new[]
                {
                    // Standard Windows installations
                    Path.Combine(programFiles, "nodejs"),
                    Path.Combine(programFilesX86, "nodejs"),
                    Path.Combine(localAppData, "Programs", "nodejs"),

                    // nvm-windows
                    Path.Combine(appData, "nvm"),
                    Path.Combine(userProfile, ".nvm"),

                    // volta
                    Path.Combine(localAppData, "Volta", "bin"),
                    Path.Combine(userProfile, ".volta", "bin"),

                    // fnm
                    Path.Combine(localAppData, "fnm"),
                    Path.Combine(userProfile, ".fnm"),

                    // Common D: drive installations (for users who install on secondary drives)
                    "D:\\nodejs",
                    "D:\\Program Files\\nodejs",
                    "D:\\Program Files (x86)\\nodejs",
                    "D:\\nvm",
                    "D:\\nvm\\nodejs",

                    // E: drive (some users use this too)
                    "E:\\nodejs",
                    "E:\\Program Files\\nodejs",
                });
            }
            else
            {
                // macOS/Linux paths
                var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
                searchPaths.AddRange(new[]
                {
                    "/opt/homebrew/bin",
                    "/usr/local/bin",
                    "/usr/bin",
                    Path.Combine(home, ".nvm", "versions", "node"),
                    Path.Combine(home, ".volta", "bin"),
                    Path.Combine(home, ".fnm"),
                    Path.Combine(home, ".npm-global", "bin"),
                });
            }

            foreach (var basePath in searchPaths)
            {
                if (Directory.Exists(basePath))
                {
                    // Direct check
                    var directPath = Path.Combine(basePath, nodeExecutable);
                    if (File.Exists(directPath))
                    {
                        SynLog.Info($"[Synaptic] Found Node.js: {directPath}");
                        return NormalizePathForJson(directPath);
                    }

                    // Check subdirectories (for version managers like nvm)
                    try
                    {
                        foreach (var subdir in Directory.GetDirectories(basePath))
                        {
                            var binPath = Path.Combine(subdir, nodeExecutable);
                            if (File.Exists(binPath))
                            {
                                SynLog.Info($"[Synaptic] Found Node.js in version manager: {binPath}");
                                return NormalizePathForJson(binPath);
                            }
                            // Also check bin subdirectory
                            binPath = Path.Combine(subdir, "bin", nodeExecutable);
                            if (File.Exists(binPath))
                            {
                                SynLog.Info($"[Synaptic] Found Node.js in version manager: {binPath}");
                                return NormalizePathForJson(binPath);
                            }
                        }
                    }
                    catch { }
                }
            }

            // 3. Try 'where' command on Windows, 'which' on Unix
            try
            {
                var process = new System.Diagnostics.Process
                {
                    StartInfo = new System.Diagnostics.ProcessStartInfo
                    {
                        FileName = Application.platform == RuntimePlatform.WindowsEditor ? "where" : "which",
                        Arguments = "node",
                        UseShellExecute = false,
                        RedirectStandardOutput = true,
                        RedirectStandardError = true,
                        CreateNoWindow = true
                    }
                };
                process.Start();
                var output = process.StandardOutput.ReadLine()?.Trim();
                process.WaitForExit();

                if (process.ExitCode == 0 && !string.IsNullOrEmpty(output) && File.Exists(output))
                {
                    SynLog.Info($"[Synaptic] Found Node.js via system command: {output}");
                    return NormalizePathForJson(output);
                }
            }
            catch { }

            // 4. Return "node" as fallback (rely on PATH)
            SynLog.Warn("[Synaptic] Node.js path not detected, using 'node' (requires PATH to be set correctly)");
            return "node";
        }

        private bool CheckAndInstallDependencies()
        {
            try
            {
                SynLog.Info("[Synaptic] Checking dependencies...");
                
                // Check if Newtonsoft.Json is installed
                var listRequest = Client.List();
                while (!listRequest.IsCompleted)
                {
                    System.Threading.Thread.Sleep(10);
                }
                
                if (listRequest.Status == StatusCode.Success)
                {
                    bool hasNewtonsoft = false;
                    foreach (var package in listRequest.Result)
                    {
                        if (package.name == "com.unity.nuget.newtonsoft-json")
                        {
                            hasNewtonsoft = true;
                            SynLog.Info($"[Synaptic] Newtonsoft.Json already installed: v{package.version}");
                            break;
                        }
                    }
                    
                    if (!hasNewtonsoft)
                    {
                        SynLog.Info("[Synaptic] Installing Newtonsoft.Json...");
                        
                        // Install Newtonsoft.Json
                        var addRequest = Client.Add("com.unity.nuget.newtonsoft-json");
                        
                        while (!addRequest.IsCompleted)
                        {
                            System.Threading.Thread.Sleep(10);
                        }
                        
                        if (addRequest.Status == StatusCode.Success)
                        {
                            SynLog.Info("[Synaptic] Newtonsoft.Json installed successfully");
                            
                            // Wait for compilation
                            EditorUtility.DisplayDialog(
                                "Dependencies Installed",
                                "Newtonsoft.Json has been installed. Unity will now recompile.\n\nPlease run setup again after compilation completes.",
                                "OK"
                            );
                            
                            return false; // Return false to stop setup and wait for recompilation
                        }
                        else if (addRequest.Status == StatusCode.Failure)
                        {
                            Debug.LogError($"[Synaptic] Failed to install Newtonsoft.Json: {addRequest.Error.message}");
                            return false;
                        }
                    }
                }
                
                // Check TextMeshPro
                bool hasTMP = false;
                if (listRequest.Status == StatusCode.Success)
                {
                    foreach (var package in listRequest.Result)
                    {
                        if (package.name == "com.unity.textmeshpro")
                        {
                            hasTMP = true;
                            SynLog.Info($"[Synaptic] TextMeshPro already installed: v{package.version}");
                            break;
                        }
                    }
                }
                
                if (!hasTMP)
                {
                    SynLog.Warn("[Synaptic] TextMeshPro not found. Some features may not work properly.");
                }
                
                return true;
            }
            catch (Exception e)
            {
                Debug.LogError($"[Synaptic] Dependency check error: {e.Message}");
                return true; // Continue anyway
            }
        }
        
    }
}