"""MCP server management handler mixin for IeumApp."""
# ruff: noqa: BLE001, PLR0912, PLR2004, S110

from __future__ import annotations

import asyncio
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
    pass


class McpHandlerMixin:
    """MCP server management methods for IeumApp."""

    async def _cmd_mcp(self, command: str) -> None:
        """Handle /mcp command for MCP server management.

        Subcommands:
            /mcp              - List configured MCP servers
            /mcp add <name> stdio <cmd> [args] - Add stdio MCP server
            /mcp add <name> http <url>         - Add http MCP server
            /mcp remove <name>                 - Remove MCP server
        """
        from ieum.widgets.messages import SystemMessage, UserMessage

        await self._mount_message(UserMessage(command))

        parts = command.strip().split()

        if len(parts) == 1 or (len(parts) == 2 and parts[1].lower() == "list"):
            # /mcp or /mcp list - show configured servers
            await self._mcp_list()
        elif len(parts) >= 2 and parts[1].lower() == "add":
            # /mcp add <name> [stdio|http] [config...]
            if len(parts) < 3:
                await self._mcp_add(None)
            elif len(parts) == 3:
                # /mcp add <name> - show help for this server
                await self._mcp_add(parts[2])
            elif len(parts) >= 4:
                # /mcp add <name> <transport> <config...>
                name = parts[2]
                transport = parts[3].lower()
                config_args = parts[4:] if len(parts) > 4 else []
                await self._mcp_add_with_config(name, transport, config_args)
        elif len(parts) >= 2 and parts[1].lower() in ("remove", "rm"):
            # /mcp remove <name>
            if len(parts) < 3:
                await self._mount_message(
                    SystemMessage("Usage: /mcp remove <server-name>")
                )
            else:
                await self._mcp_remove(parts[2])
        elif len(parts) >= 2 and parts[1].lower() == "reload":
            # /mcp reload - reload MCP servers without restart
            await self._mcp_reload()
        else:
            await self._mount_message(
                SystemMessage(
                    "MCP 명령어:\n"
                    "  /mcp                            서버 목록\n"
                    "  /mcp add <이름> stdio <cmd> ... 로컬 서버 추가\n"
                    "  /mcp add <이름> http <url>      HTTP 서버 추가\n"
                    "  /mcp remove <이름>              서버 제거\n"
                    "  /mcp reload                     서버 다시 로드"
                )
            )

    async def _mcp_list(self) -> None:
        """List configured MCP servers with connection status."""
        from ieum.mcp import load_mcp_config
        from ieum.mcp.config import get_global_mcp_config_path, get_project_mcp_config_path
        from ieum.widgets.messages import SystemMessage

        config = load_mcp_config()

        # Build help section
        lines = [
            "MCP 명령어:",
            "  /mcp                            서버 목록 및 상태",
            "  /mcp add <이름> stdio <cmd> ... 로컬 서버 추가",
            "  /mcp add <이름> http <url>      HTTP 서버 추가",
            "  /mcp remove <이름>              서버 제거",
            "  /mcp reload                     서버 다시 로드",
            "",
        ]

        if not config:
            global_path = get_global_mcp_config_path()
            lines.append("서버 목록: (없음)")
            lines.append("")
            lines.append(f"설정 파일: {global_path}")
            await self._mount_message(SystemMessage("\n".join(lines)))
            return

        # Check connection status for each server
        connection_status = await self._check_mcp_connections(config)

        lines.append("서버 목록:")
        for name, server_config in config.items():
            transport = server_config.get("transport", "stdio")
            is_connected = connection_status.get(name, False)
            status_icon = "🟢" if is_connected else "🔴"

            if transport == "stdio":
                cmd = server_config.get("command", "")
                args = server_config.get("args", [])
                cmd_str = f"{cmd} {' '.join(args[:2])}" if args else cmd
                if len(args) > 2:
                    cmd_str += " ..."
                lines.append(f"  {status_icon} {name} (stdio)")
                lines.append(f"      {cmd_str}")
            elif transport == "http":
                url = server_config.get("url", "")
                lines.append(f"  {status_icon} {name} (http)")
                lines.append(f"      {url}")

        # Show config file locations
        lines.append("")
        global_path = get_global_mcp_config_path()
        project_path = get_project_mcp_config_path()
        lines.append(f"전역 설정: {global_path}")
        if project_path:
            lines.append(f"프로젝트 설정: {project_path}")

        await self._mount_message(SystemMessage("\n".join(lines)))

    async def _mcp_reload(self) -> None:
        """Reload MCP servers without restarting the app."""
        from ieum.mcp import load_mcp_config
        from ieum.mcp.client import MCPClientManager, _global_manager
        from ieum.widgets.messages import SystemMessage

        await self._mount_message(SystemMessage("MCP 서버 다시 로드 중..."))

        # Close existing connections
        import ieum.mcp.client as mcp_client_module

        if mcp_client_module._global_manager is not None:
            try:
                await mcp_client_module._global_manager.close()
            except Exception:
                pass
            mcp_client_module._global_manager = None

        # Reload configuration
        config = load_mcp_config()

        if not config:
            await self._mount_message(SystemMessage("설정된 MCP 서버가 없습니다."))
            return

        # Create new manager and load tools
        new_manager = MCPClientManager(config)
        mcp_client_module._global_manager = new_manager

        try:
            tools = await new_manager.get_tools()
            tool_names = [t.name for t in tools]
            tool_display = ", ".join(tool_names[:5])
            if len(tool_names) > 5:
                tool_display += f" 외 {len(tool_names) - 5}개"
            await self._mount_message(
                SystemMessage(
                    f"✓ MCP 서버 로드 완료\n"
                    f"  서버: {', '.join(config.keys())}\n"
                    f"  도구: {len(tools)}개 ({tool_display})"
                )
            )
        except Exception as e:
            await self._mount_message(
                SystemMessage(f"✗ MCP 로드 실패: {e}")
            )

    async def _check_mcp_connections(
        self, config: dict[str, Any]
    ) -> dict[str, bool]:
        """Check connection status for each MCP server.

        Args:
            config: MCP server configurations

        Returns:
            Dictionary mapping server names to connection status (True/False)
        """
        status: dict[str, bool] = {}

        try:
            from langchain_mcp_adapters.client import MultiServerMCPClient
        except ImportError:
            # langchain-mcp-adapters not installed, all servers show as disconnected
            return {name: False for name in config}

        # Try to connect to each server individually
        for name, server_config in config.items():
            try:
                single_config = {name: server_config}
                client = MultiServerMCPClient(single_config)
                # Try to get tools (this will attempt connection)
                tools = await asyncio.wait_for(client.get_tools(), timeout=5.0)
                status[name] = len(tools) >= 0  # Connected if no exception
                try:
                    await client.close()
                except Exception:
                    pass
            except Exception:
                status[name] = False

        return status

    async def _mcp_add(self, name: str | None) -> None:
        """Add a new MCP server interactively."""
        import json
        from ieum.mcp.config import get_global_mcp_config_path
        from ieum.widgets.messages import SystemMessage

        if not name:
            await self._mount_message(
                SystemMessage(
                    "MCP 서버 추가:\n\n"
                    "1. stdio 서버 (로컬 프로세스):\n"
                    "   /mcp add <이름> 후 command와 args 입력\n\n"
                    "2. http 서버:\n"
                    "   /mcp add <이름> 후 URL 입력\n\n"
                    "예시:\n"
                    "  /mcp add filesystem\n"
                    "  /mcp add weather"
                )
            )
            return

        # Get the config file path
        config_path = get_global_mcp_config_path()

        # Load existing config
        existing_config: dict = {}
        if config_path.exists():
            try:
                with open(config_path, encoding="utf-8") as f:
                    existing_config = json.load(f)
            except (json.JSONDecodeError, OSError):
                pass

        if "mcpServers" not in existing_config:
            existing_config["mcpServers"] = {}

        # Check if server already exists
        if name in existing_config["mcpServers"]:
            await self._mount_message(
                SystemMessage(f"'{name}' 서버가 이미 존재합니다. 먼저 /mcp remove {name} 하세요.")
            )
            return

        # Ask for transport type via agent message
        await self._mount_message(
            SystemMessage(
                f"'{name}' MCP 서버 추가\n\n"
                "다음 중 하나를 입력하세요:\n\n"
                "1. stdio 서버 (npx 등):\n"
                f"   /mcp add {name} stdio <command> [args...]\n"
                f"   예: /mcp add {name} stdio npx -y @anthropic/mcp-server-filesystem /home\n\n"
                "2. http 서버:\n"
                f"   /mcp add {name} http <url>\n"
                f"   예: /mcp add {name} http http://localhost:8000/mcp"
            )
        )

    async def _mcp_add_with_config(
        self, name: str, transport: str, config_args: list[str]
    ) -> None:
        """Add MCP server with provided configuration."""
        import json
        from ieum.mcp.config import get_global_mcp_config_path
        from ieum.widgets.messages import SystemMessage

        config_path = get_global_mcp_config_path()

        # Ensure directory exists
        config_path.parent.mkdir(parents=True, exist_ok=True)

        # Load existing config
        existing_config: dict = {}
        if config_path.exists():
            try:
                with open(config_path, encoding="utf-8") as f:
                    existing_config = json.load(f)
            except (json.JSONDecodeError, OSError):
                pass

        if "mcpServers" not in existing_config:
            existing_config["mcpServers"] = {}

        # Build server config
        if transport == "stdio":
            if not config_args:
                await self._mount_message(SystemMessage("stdio 서버는 command가 필요합니다."))
                return
            server_config = {
                "transport": "stdio",
                "command": config_args[0],
                "args": config_args[1:] if len(config_args) > 1 else [],
            }
        elif transport == "http":
            if not config_args:
                await self._mount_message(SystemMessage("http 서버는 URL이 필요합니다."))
                return
            server_config = {
                "transport": "http",
                "url": config_args[0],
            }
        else:
            await self._mount_message(
                SystemMessage(f"알 수 없는 transport: {transport}. 'stdio' 또는 'http' 사용")
            )
            return

        # Save config
        existing_config["mcpServers"][name] = server_config

        try:
            with open(config_path, "w", encoding="utf-8") as f:
                json.dump(existing_config, f, indent=2, ensure_ascii=False)
            await self._mount_message(
                SystemMessage(f"✓ '{name}' MCP 서버가 추가되었습니다.")
            )
            # Auto-reload to register tools immediately
            await self._mcp_reload()
        except OSError as e:
            await self._mount_message(SystemMessage(f"설정 저장 실패: {e}"))

    async def _mcp_remove(self, name: str) -> None:
        """Remove an MCP server."""
        import json
        from ieum.mcp.config import get_global_mcp_config_path
        from ieum.widgets.messages import SystemMessage

        config_path = get_global_mcp_config_path()

        if not config_path.exists():
            await self._mount_message(SystemMessage("MCP 설정 파일이 없습니다."))
            return

        try:
            with open(config_path, encoding="utf-8") as f:
                config = json.load(f)
        except (json.JSONDecodeError, OSError) as e:
            await self._mount_message(SystemMessage(f"설정 파일 읽기 실패: {e}"))
            return

        servers = config.get("mcpServers", {})
        if name not in servers:
            await self._mount_message(
                SystemMessage(f"'{name}' 서버를 찾을 수 없습니다.\n/mcp 로 목록을 확인하세요.")
            )
            return

        del servers[name]

        try:
            with open(config_path, "w", encoding="utf-8") as f:
                json.dump(config, f, indent=2, ensure_ascii=False)
            await self._mount_message(
                SystemMessage(f"✓ '{name}' MCP 서버가 제거되었습니다.")
            )
            # Auto-reload to unregister tools immediately
            await self._mcp_reload()
        except OSError as e:
            await self._mount_message(SystemMessage(f"설정 저장 실패: {e}"))
