# -*- coding: utf-8 -*-
"""extension_context 模块测试"""
from unittest.mock import MagicMock

import pytest

from abyss.extension_context import ExtensionContext, MCPToolProxy
from abyss.tools.registry import ToolRegistry
from abyss.tools.base import Tool


class FakeTool(Tool):
    @property
    def name(self) -> str:
        return "fake_tool"

    @property
    def description(self) -> str:
        return "A fake tool"

    @property
    def parameters(self) -> dict:
        return {"type": "object", "properties": {}}

    def execute(self, **kwargs) -> dict:
        return {"success": True}


class TestExtensionContext:
    """ExtensionContext 门面模式测试"""

    def test_register_tool(self):
        """通过 context 注册工具到 registry。"""
        reg = ToolRegistry()
        ctx = ExtensionContext(reg, source="test")

        tool = FakeTool()
        ctx.register_tool(tool)

        assert "fake_tool" in reg

    def test_tool_source_tracking(self):
        """记录工具来源。"""
        reg = ToolRegistry()
        ctx = ExtensionContext(reg, source="mcp__test-server")

        ctx.register_tool(FakeTool())
        assert ctx.list_owned_tools() == ["fake_tool"]

    def test_unregister_all_owns(self):
        """注销该 context 拥有的所有工具。"""
        reg = ToolRegistry()
        ctx1 = ExtensionContext(reg, source="mcp__server-a")
        ctx2 = ExtensionContext(reg, source="mcp__server-b")

        class ToolA(Tool):
            @property
            def name(self) -> str:
                return "tool_a"
            @property
            def description(self) -> str:
                return "a"
            @property
            def parameters(self) -> dict:
                return {"type": "object", "properties": {}}
            def execute(self, **kw) -> dict:
                return {"ok": True}

        class ToolB(Tool):
            @property
            def name(self) -> str:
                return "tool_b"
            @property
            def description(self) -> str:
                return "b"
            @property
            def parameters(self) -> dict:
                return {"type": "object", "properties": {}}
            def execute(self, **kw) -> dict:
                return {"ok": True}

        ctx1.register_tool(ToolA())
        ctx2.register_tool(ToolB())

        assert "tool_a" in reg
        assert "tool_b" in reg

        ctx1.unregister_all()

        assert "tool_a" not in reg
        assert "tool_b" in reg  # ctx2 的不受影响

    def test_cannot_unregister_not_owned(self):
        """不能注销不属于自己的工具。"""
        reg = ToolRegistry()
        ctx = ExtensionContext(reg, source="mcp__s")

        reg.register(FakeTool())
        # 该工具不是通过 ctx 注册的，不应在 owned 列表中
        assert "fake_tool" not in ctx.list_owned_tools()

    def test_register_tool_with_existing_name(self):
        """同名工具已存在时不覆盖，返回 None 并警告。"""
        reg = ToolRegistry()
        reg.register(FakeTool())  # 先注册一个 fake_tool

        ctx = ExtensionContext(reg, source="test")
        result = ctx.register_tool(FakeTool())  # 同名再注册
        assert result is None

    def test_source_field(self):
        """source 字段可读。"""
        ctx = ExtensionContext(ToolRegistry(), source="mcp__github")
        assert ctx.source == "mcp__github"


class TestMCPToolProxy:
    """MCPToolProxy 测试"""

    def test_proxy_dispatches_to_mcp(self):
        """工具调用委托到 MCPClientManager。"""
        mcp = MagicMock()
        mcp.get_server_for_tool.return_value = ("github", "search_repos")
        mcp.call_tool.return_value = {"success": True, "result": "found"}

        proxy = MCPToolProxy(
            full_name="mcp__github__search_repos",
            description="Search repos",
            input_schema={"type": "object", "properties": {}},
            mcp=mcp,
        )
        assert proxy.name == "mcp__github__search_repos"

        result = proxy.execute(query="test")
        assert result["success"] is True
        mcp.call_tool.assert_called_once_with("github", "search_repos", {"query": "test"})
