"""Shared mock MCP transport for Behave and Robot Framework tests."""

from __future__ import annotations

import json
from typing import Any

from cleveragents.mcp.adapter import MCPServerConfig, MCPTransport


class MockMCPTransport(MCPTransport):
    """In-memory mock transport simulating an MCP server.

    Supports configurable tools, connection failures, invocation results,
    invocation errors, and tool-level timeouts for deterministic testing.
    """

    def __init__(
        self,
        tools: list[dict[str, Any]] | None = None,
        *,
        fail_connect: bool = False,
        invoke_results: dict[str, dict[str, Any]] | None = None,
        invoke_errors: dict[str, str] | None = None,
        timeout_tools: set[str] | None = None,
    ) -> None:
        self._tools = tools or []
        self._fail_connect = fail_connect
        self._invoke_results = invoke_results or {}
        self._invoke_errors = invoke_errors or {}
        self._timeout_tools = timeout_tools or set()
        self._connected = False

    def connect(self, config: MCPServerConfig) -> dict[str, Any]:
        if self._fail_connect:
            msg = "Mock connection refused"
            raise ConnectionRefusedError(msg)
        self._connected = True
        return {"capabilities": {"tools": True}}

    def call(self, method: str, params: dict[str, Any]) -> dict[str, Any]:
        if method == "tools/list":
            return {"tools": list(self._tools)}

        if method == "tools/call":
            tool_name = params.get("name", "")

            if tool_name in self._timeout_tools:
                msg = f"Tool '{tool_name}' exceeded timeout"
                raise TimeoutError(msg)

            if tool_name in self._invoke_errors:
                return {
                    "isError": True,
                    "content": [
                        {"type": "text", "text": self._invoke_errors[tool_name]}
                    ],
                }

            if tool_name in self._invoke_results:
                # MCP 1.4.0: ``content`` is a list of ContentItem dicts.
                # Wrap the caller-supplied result dict as a text ContentItem
                # so the mock accurately reflects real server behaviour.
                payload = self._invoke_results[tool_name]
                content_item: dict[str, Any] = {
                    "type": "text",
                    "text": json.dumps(payload),
                }
                return {"content": [content_item]}

            return {"content": [{"type": "text", "text": "ok"}]}

        return {}

    def close(self) -> None:
        self._connected = False

    def add_tool(self, tool: dict[str, Any]) -> None:
        self._tools.append(tool)
