import asyncio

import pytest

from mcpbridge.config import LLMConfig
from mcpbridge.exceptions import ConfigValidationError
from mcpbridge.registry import DynamicToolRegistry


class RegistryTestTransport:
    """Fake MCP transport that returns canned JSON-RPC responses."""

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

    @property
    def is_connected(self) -> bool:
        return self._connected

    async def connect(self) -> None:
        self._connected = True

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

    async def send_notification(self, method: str, params: dict):
        return

    async def send(self, message: dict):
        method = message.get("method")
        if method == "initialize":
            return {"jsonrpc": "2.0", "id": message.get("id"), "result": {}}
        if method == "tools/list":
            tool_schema = {
                "$schema": "http://json-schema.org/draft-07/schema#",
                "type": "object",
                "properties": {"query": {"type": "string", "description": "q"}},
                "required": ["query"],
                "additionalProperties": False,
            }
            return {"jsonrpc": "2.0", "id": message.get("id"), "result": {"tools": [{"name": "search", "description": "Search", "inputSchema": tool_schema}]}}
        if method == "resources/list":
            return {"jsonrpc": "2.0", "id": message.get("id"), "result": {"resources": []}}
        if method == "prompts/list":
            return {"jsonrpc": "2.0", "id": message.get("id"), "result": {"prompts": []}}

        raise AssertionError(f"Unexpected method: {method}")


def test_discover_and_for_llm_conversions_prefix_namespace():
    async def _run():
        transport = RegistryTestTransport()
        await transport.connect()

        reg = DynamicToolRegistry(server_name="srv", namespace_strategy="prefix")
        await reg.discover(transport)

        tool_keys = list(reg.tools.keys())
        assert tool_keys == ["srv__search"]

        openai_tools = reg.for_llm("openai")
        assert openai_tools[0]["type"] == "function"
        assert openai_tools[0]["function"]["name"] == "srv__search"
        assert openai_tools[0]["function"]["parameters"]["properties"]["query"]["type"] == "string"

        anthropic_tools = reg.for_llm("anthropic")
        assert anthropic_tools[0]["name"] == "srv__search"
        assert "input_schema" in anthropic_tools[0]

        gemini_tools = reg.for_llm("gemini")
        assert len(gemini_tools) == 1
        decl = gemini_tools[0]["function_declarations"][0]
        assert decl["name"] == "srv__search"
        assert "$schema" not in decl["parameters"]
        assert "additionalProperties" not in decl["parameters"]

        cohere_tools = reg.for_llm("cohere")
        assert cohere_tools[0]["name"] == "srv__search"
        pd = cohere_tools[0]["parameter_definitions"]["query"]
        assert pd["type"] == "string"
        assert pd["required"] is True

        bedrock_tools = reg.for_llm("bedrock")
        assert bedrock_tools[0]["toolSpec"]["name"] == "srv__search"
        assert bedrock_tools[0]["toolSpec"]["inputSchema"]["json"]["type"] == "object"

    asyncio.run(_run())


def test_merge_error_strategy_raises():
    reg1 = DynamicToolRegistry(server_name="a", namespace_strategy="error")
    reg1.tools = {
        "t": type("T", (), {"name": "t", "description": "", "input_schema": {}, "server_name": "a", "namespaced_name": "t"})(),
    }
    reg2 = DynamicToolRegistry(server_name="b", namespace_strategy="error")
    reg2.tools = {
        "t": type("T", (), {"name": "t", "description": "", "input_schema": {}, "server_name": "b", "namespaced_name": "t"})(),
    }
    merged = DynamicToolRegistry(server_name="merged", namespace_strategy="error")
    merged.tools = {}
    merged.merge(reg1)
    with pytest.raises(ConfigValidationError):
        merged.merge(reg2)


def test_merge_last_wins():
    reg1 = DynamicToolRegistry(server_name="a", namespace_strategy="last_wins")
    reg1.tools = {
        "t": type("T", (), {"name": "t", "description": "", "input_schema": {}, "server_name": "a", "namespaced_name": "t"})(),
    }
    reg2 = DynamicToolRegistry(server_name="b", namespace_strategy="last_wins")
    reg2.tools = {
        "t": type("T", (), {"name": "t", "description": "new", "input_schema": {}, "server_name": "b", "namespaced_name": "t"})(),
    }
    merged = DynamicToolRegistry(server_name="merged", namespace_strategy="last_wins")
    merged.tools = {}
    merged.merge(reg1)
    merged.merge(reg2)
    assert merged.tools["t"].server_name == "b"

