"""MCP Client - 调用外部 MCP 工具服务器"""

import logging
from typing import Any

import httpx

from agentkit.mcp.transport import HTTPTransport, SSETransport, StdioTransport, Transport
from agentkit.tools.base import Tool

logger = logging.getLogger(__name__)


class MCPClient:
    """MCP Client - 连接外部 MCP Server 并调用工具

    支持两种模式：
    1. 通过 Transport 层发送 JSON-RPC 请求（推荐）
    2. 直接 HTTP 调用（向后兼容）
    """

    def __init__(
        self,
        server_url: str,
        timeout: int = 30,
        transport: Transport | None = None,
    ):
        self._server_url = server_url.rstrip("/")
        self._timeout = timeout
        self._tools_cache: list[dict] | None = None
        self._transport = transport

    @classmethod
    def from_transport(cls, transport: Transport) -> "MCPClient":
        """从 Transport 实例创建 MCPClient"""
        if isinstance(transport, HTTPTransport):
            server_url = transport._endpoint
        elif isinstance(transport, SSETransport):
            server_url = transport._endpoint
        elif isinstance(transport, StdioTransport):
            server_url = f"stdio://{transport._command}"
        else:
            server_url = ""
        return cls(server_url=server_url, transport=transport)

    async def list_tools(self) -> list[dict]:
        """列出远程 MCP Server 上的工具"""
        if self._transport is not None:
            if not self._transport.is_connected:
                await self._transport.connect()
            result = await self._transport.send_request("tools/list")
            tools = result.get("tools", []) if isinstance(result, dict) else []
            self._tools_cache = tools
            return self._tools_cache

        async with httpx.AsyncClient(timeout=self._timeout) as client:
            response = await client.get(f"{self._server_url}/tools/list")
            response.raise_for_status()
            data = response.json()
            self._tools_cache = data.get("tools", [])
            return self._tools_cache

    async def call_tool(self, tool_name: str, arguments: dict) -> dict:
        """调用远程 MCP 工具"""
        if self._transport is not None:
            if not self._transport.is_connected:
                await self._transport.connect()
            return await self._transport.send_request(
                "tools/call",
                params={"name": tool_name, "arguments": arguments},
            )

        async with httpx.AsyncClient(timeout=self._timeout) as client:
            response = await client.post(
                f"{self._server_url}/tools/call",
                json={"name": tool_name, "arguments": arguments},
            )
            response.raise_for_status()
            return response.json()

    def as_tool(self, tool_name: str, description: str = "") -> "MCPTool":
        """将远程 MCP 工具包装为本地 Tool 对象"""
        return MCPTool(
            name=tool_name,
            description=description,
            client=self,
        )


class MCPTool(Tool):
    """MCP 工具 - 通过 MCP Client 调用远程工具"""

    def __init__(
        self,
        name: str,
        description: str,
        client: MCPClient,
        input_schema: dict[str, Any] | None = None,
        output_schema: dict[str, Any] | None = None,
        version: str = "1.0.0",
        tags: list[str] | None = None,
    ):
        super().__init__(
            name=name,
            description=description,
            input_schema=input_schema,
            output_schema=output_schema,
            version=version,
            tags=tags or ["mcp"],
        )
        self._client = client

    async def execute(self, **kwargs) -> dict:
        result = await self._client.call_tool(self.name, kwargs)
        # 解析 MCP 响应格式
        if "content" in result:
            for item in result["content"]:
                if item.get("type") == "text":
                    import json
                    try:
                        return json.loads(item["text"])
                    except json.JSONDecodeError:
                        return {"result": item["text"]}
        return result
