"""MCP Bridge plugin — connect to external MCP servers and expose their tools."""

from __future__ import annotations

import logging
from typing import Any

import httpx

from agent_scout.plugins.base import Plugin, PluginConfig, PluginParam, ToolSpec

logger = logging.getLogger(__name__)


class MCPServerConnection:
    """Represents a connection to a single MCP server."""

    def __init__(
        self,
        name: str,
        endpoint: str,
        enabled: bool = True,
        api_key: str = "",
    ) -> None:
        self.name = name
        self.endpoint = endpoint.rstrip("/")
        self.enabled = enabled
        self.api_key = api_key
        self.tools: list[ToolSpec] = []

    async def discover_tools(self) -> list[ToolSpec]:
        """Fetch tool list from the MCP server."""
        try:
            headers: dict[str, str] = {}
            if self.api_key:
                headers["Authorization"] = f"Bearer {self.api_key}"

            async with httpx.AsyncClient() as client:
                resp = await client.post(
                    f"{self.endpoint}/tools/list",
                    json={},
                    headers=headers,
                    timeout=10,
                )
                resp.raise_for_status()
                data = resp.json()

            self.tools = []
            for tool_data in data.get("tools", []):
                params: list[PluginParam] = []
                props = tool_data.get("inputSchema", {}).get("properties", {})
                required = tool_data.get("inputSchema", {}).get("required", [])

                for pname, pschema in props.items():
                    params.append(
                        PluginParam(
                            name=pname,
                            description=pschema.get("description", ""),
                            param_type=pschema.get("type", "string"),
                            required=pname in required,
                        )
                    )

                tool_name = f"mcp_{self.name}_{tool_data['name']}"
                self.tools.append(
                    ToolSpec(
                        name=tool_name,
                        description=tool_data.get("description", ""),
                        parameters=params,
                    )
                )

            return self.tools
        except Exception:
            logger.exception("Failed to discover tools from MCP server '%s'", self.name)
            return []

    async def call_tool(self, original_tool_name: str, tool_input: dict[str, Any]) -> str:
        """Call a tool on the MCP server."""
        try:
            headers: dict[str, str] = {}
            if self.api_key:
                headers["Authorization"] = f"Bearer {self.api_key}"

            async with httpx.AsyncClient() as client:
                resp = await client.post(
                    f"{self.endpoint}/tools/call",
                    json={"name": original_tool_name, "arguments": tool_input},
                    headers=headers,
                    timeout=30,
                )
                resp.raise_for_status()
                data = resp.json()

            # Extract content from MCP response
            content_parts = data.get("content", [])
            results: list[str] = []
            for part in content_parts:
                if part.get("type") == "text":
                    results.append(part.get("text", ""))
                elif part.get("type") == "image":
                    results.append(f"[Image: {part.get('mimeType', 'image')}]")
            return "\n".join(results) if results else str(data)
        except Exception as e:
            return f"MCP tool call failed: {e}"


class MCPBridgePlugin(Plugin):
    """Bridge to external MCP (Model Context Protocol) servers.

    Connects to one or more MCP servers, discovers their tools,
    and exposes them to the agent as native plugin tools.
    """

    def __init__(self, config: PluginConfig | None = None) -> None:
        super().__init__(config)
        self._servers: list[MCPServerConnection] = []
        self._tool_to_server: dict[str, tuple[MCPServerConnection, str]] = {}

    @property
    def name(self) -> str:
        return "mcp_bridge"

    @property
    def description(self) -> str:
        return "Connect to MCP servers and use their tools"

    def get_tools(self) -> list[ToolSpec]:
        tools: list[ToolSpec] = []
        for server in self._servers:
            if server.enabled:
                tools.extend(server.tools)
        return tools

    async def on_load(self) -> None:
        """Build server connections from config."""
        servers_config = self._config.settings.get("servers", [])
        for srv in servers_config:
            conn = MCPServerConnection(
                name=srv.get("name", "unknown"),
                endpoint=srv.get("endpoint", ""),
                enabled=srv.get("enabled", True),
                api_key=srv.get("api_key", ""),
            )
            self._servers.append(conn)

        # Discover tools from all enabled servers
        for server in self._servers:
            if server.enabled:
                tools = await server.discover_tools()
                for tool in tools:
                    # Map tool name back to server + original name
                    original_name = tool.name.replace(f"mcp_{server.name}_", "", 1)
                    self._tool_to_server[tool.name] = (server, original_name)

    async def on_unload(self) -> None:
        self._servers.clear()
        self._tool_to_server.clear()

    def add_server(self, server: MCPServerConnection) -> None:
        """Add a server connection manually (useful for testing)."""
        self._servers.append(server)
        for tool in server.tools:
            original_name = tool.name.replace(f"mcp_{server.name}_", "", 1)
            self._tool_to_server[tool.name] = (server, original_name)

    async def execute(self, tool_name: str, tool_input: dict[str, Any]) -> str:
        mapping = self._tool_to_server.get(tool_name)
        if not mapping:
            return f"Unknown MCP tool: {tool_name}"

        server, original_name = mapping
        if not server.enabled:
            return f"MCP server '{server.name}' is disabled"

        return await server.call_tool(original_name, tool_input)

    async def health_check(self) -> bool:
        return self.enabled and len(self._servers) > 0
