"""MCP client manager using langchain-mcp-adapters.

Provides integration with MCP servers through the MultiServerMCPClient,
converting MCP tools to LangChain-compatible tools.
"""

from __future__ import annotations

import asyncio
from typing import TYPE_CHECKING

from ieum.mcp.config import load_mcp_config, MCPServerConfig

if TYPE_CHECKING:
    from langchain_core.tools import BaseTool


class MCPClientManager:
    """Manager for MCP client connections.

    Handles loading configuration and creating MultiServerMCPClient
    to connect to configured MCP servers.

    Example:
        ```python
        manager = MCPClientManager()
        tools = await manager.get_tools()
        # Use tools with your agent
        ```
    """

    def __init__(self, config: dict[str, MCPServerConfig] | None = None) -> None:
        """Initialize MCP client manager.

        Args:
            config: Optional server configurations. If None, loads from config files.
        """
        self._config = config if config is not None else load_mcp_config()
        self._client = None
        self._tools: list[BaseTool] | None = None

    @property
    def has_servers(self) -> bool:
        """Check if any MCP servers are configured."""
        return len(self._config) > 0

    @property
    def server_names(self) -> list[str]:
        """Get list of configured server names."""
        return list(self._config.keys())

    async def get_tools(self) -> list[BaseTool]:
        """Get LangChain tools from all configured MCP servers.

        Returns:
            List of LangChain-compatible tools from MCP servers.
            Returns empty list if langchain-mcp-adapters is not installed
            or no servers are configured.
        """
        if self._tools is not None:
            return self._tools

        if not self.has_servers:
            self._tools = []
            return self._tools

        try:
            from langchain_mcp_adapters.client import MultiServerMCPClient
        except ImportError:
            # langchain-mcp-adapters not installed
            self._tools = []
            return self._tools

        try:
            # Create client with server configs
            self._client = MultiServerMCPClient(self._config)
            self._tools = await self._client.get_tools()
            return self._tools
        except Exception as e:
            # Log error but don't crash
            print(f"Warning: Failed to load MCP tools: {e}")
            self._tools = []
            return self._tools

    def get_tools_sync(self) -> list[BaseTool]:
        """Synchronous wrapper for get_tools().

        Returns:
            List of LangChain-compatible tools from MCP servers.
        """
        try:
            loop = asyncio.get_event_loop()
            if loop.is_running():
                # If we're already in an async context, create a new thread
                import concurrent.futures
                with concurrent.futures.ThreadPoolExecutor() as executor:
                    future = executor.submit(asyncio.run, self.get_tools())
                    return future.result()
            else:
                return loop.run_until_complete(self.get_tools())
        except RuntimeError:
            # No event loop, create one
            return asyncio.run(self.get_tools())

    async def close(self) -> None:
        """Close all MCP client connections."""
        if self._client is not None:
            try:
                await self._client.close()
            except Exception:
                pass
            self._client = None
        self._tools = None


# Global instance for convenience
_global_manager: MCPClientManager | None = None


def get_mcp_manager() -> MCPClientManager:
    """Get or create the global MCP client manager.

    Returns:
        The global MCPClientManager instance.
    """
    global _global_manager
    if _global_manager is None:
        _global_manager = MCPClientManager()
    return _global_manager


def get_mcp_tools() -> list[BaseTool]:
    """Get MCP tools from the global manager (sync).

    Convenience function for getting MCP tools synchronously.

    Returns:
        List of LangChain-compatible tools from configured MCP servers.
    """
    return get_mcp_manager().get_tools_sync()


async def get_mcp_tools_async() -> list[BaseTool]:
    """Get MCP tools from the global manager (async).

    Convenience function for getting MCP tools asynchronously.

    Returns:
        List of LangChain-compatible tools from configured MCP servers.
    """
    return await get_mcp_manager().get_tools()
