"""Generic MCP client — connects to any MCP server via HTTP.

Replaces Cursor as the bridge for Giga, Zo, and other MCP providers.
"""

from __future__ import annotations

import logging
from typing import Any

import httpx
from pydantic import AnyUrl

logger = logging.getLogger(__name__)


class MCPClient:
    """Generic MCP client — connects to any MCP server via HTTP transport.

    Uses the MCP Python SDK's streamable HTTP transport.
    Supports: tools (list/call), resources (list/read).
    """

    def __init__(
        self,
        url: str,
        *,
        headers: dict[str, str] | None = None,
        timeout: float = 60.0,
    ) -> None:
        """Initialize MCP client.

        Args:
            url: MCP endpoint URL (e.g., https://mcp.gigamind.dev/mcp).
            headers: Optional HTTP headers (e.g., Authorization: Bearer TOKEN).
            timeout: Request timeout in seconds.
        """
        self.url = url.rstrip("/")
        self.headers = headers or {}
        self.timeout = timeout

    async def call_tool(self, tool_name: str, args: dict[str, Any] | None = None) -> dict[str, Any]:
        """Call an MCP tool by name.

        Args:
            tool_name: Name of the tool to invoke.
            args: Tool arguments (must match the tool's schema).

        Returns:
            Parsed result dict. For text content, returns {"text": "..."}.
            For structured content, returns the structured object.
            On error, returns {"error": "message"}.

        Raises:
            MCPConnectionError: When the MCP server is unreachable.
        """
        try:
            from mcp import ClientSession
            from mcp.client.streamable_http import streamable_http_client
        except ImportError as e:
            return {"error": f"MCP SDK not installed: pip install vastian-network[mcp] — {e}"}

        args = args or {}
        async with (
            self._http_client() as client,
            streamable_http_client(self.url, http_client=client, terminate_on_close=True) as (
                read_stream,
                write_stream,
                _,
            ),
            ClientSession(read_stream, write_stream) as session,
        ):
            await session.initialize()
            result = await session.call_tool(tool_name, arguments=args)
            if result.isError:
                return {"error": result.content[0].text if result.content else str(result)}
            # Extract text from content
            text_parts: list[str] = []
            structured: dict[str, Any] | None = None
            if result.content:
                for item in result.content:
                    if hasattr(item, "text"):
                        text_parts.append(getattr(item, "text", ""))
                    if result.structuredContent:
                        structured = result.structuredContent
            out: dict[str, Any] = {}
            if text_parts:
                out["text"] = "\n".join(text_parts)
            if structured:
                out["structured"] = structured
            return out if out else {"text": ""}

    async def list_tools(self) -> list[dict[str, Any]]:
        """List available tools from the MCP server.

        Returns:
            List of tool definitions (name, description, inputSchema).
        """
        try:
            from mcp import ClientSession
            from mcp.client.streamable_http import streamable_http_client
        except ImportError:
            return []

        async with (
            self._http_client() as client,
            streamable_http_client(self.url, http_client=client, terminate_on_close=True) as (
                read_stream,
                write_stream,
                _,
            ),
            ClientSession(read_stream, write_stream) as session,
        ):
            await session.initialize()
            result = await session.list_tools()
            return [
                {
                    "name": t.name,
                    "description": t.description or "",
                    "inputSchema": t.inputSchema or {},
                }
                for t in result.tools
            ]

    async def list_resources(self) -> list[dict[str, Any]]:
        """List available resources from the MCP server.

        Returns:
            List of resource metadata (uri, name, description, mimeType).
        """
        try:
            from mcp import ClientSession
            from mcp.client.streamable_http import streamable_http_client
        except ImportError:
            return []

        async with (
            self._http_client() as client,
            streamable_http_client(self.url, http_client=client, terminate_on_close=True) as (
                read_stream,
                write_stream,
                _,
            ),
            ClientSession(read_stream, write_stream) as session,
        ):
            await session.initialize()
            result = await session.list_resources()
            return [
                {
                    "uri": str(r.uri),
                    "name": r.name or "",
                    "description": r.description or "",
                    "mimeType": getattr(r, "mimeType", None),
                }
                for r in result.resources
            ]

    async def read_resource(self, uri: str) -> dict[str, Any]:
        """Read a resource by URI.

        Args:
            uri: Resource URI (e.g., file:///path/to/file).

        Returns:
            Resource content. Typically {"contents": [{"uri": ..., "mimeType": ..., "text": "..."}]}.
            On error, returns {"error": "message"}.
        """
        try:
            from mcp import ClientSession
            from mcp.client.streamable_http import streamable_http_client
        except ImportError:
            return {"error": "MCP SDK not installed: pip install vastian-network[mcp]"}

        async with (
            self._http_client() as client,
            streamable_http_client(self.url, http_client=client, terminate_on_close=True) as (
                read_stream,
                write_stream,
                _,
            ),
            ClientSession(read_stream, write_stream) as session,
        ):
            await session.initialize()
            parsed = AnyUrl(uri)
            result = await session.read_resource(parsed)
            if result.contents:
                return {
                    "contents": [
                        {
                            "uri": str(c.uri) if c.uri else "",
                            "mimeType": c.mimeType or "",
                            "text": c.text if hasattr(c, "text") else "",
                        }
                        for c in result.contents
                    ]
                }
            return {"contents": []}

    def _http_client(self) -> httpx.AsyncClient:
        """Build httpx client with headers and timeout."""
        return httpx.AsyncClient(
            headers={**self.headers, "Accept": "application/json, text/event-stream"},
            timeout=self.timeout,
        )
