"""Tests for the _run_tool() helper that guards all MCP tool calls."""

from unittest.mock import AsyncMock, patch

import pytest


class TestMcpToolGuard:
    @pytest.mark.asyncio
    async def test_returns_error_when_no_cortex(self):
        from neo_cortex.mcp import _run_tool

        with patch("neo_cortex.mcp._cortex", None):
            result = await _run_tool("test_tool", AsyncMock())
        assert result == {"error": "no cortex available"}

    @pytest.mark.asyncio
    async def test_calls_function_when_cortex_exists(self):
        from neo_cortex.mcp import _run_tool

        fn = AsyncMock(return_value={"data": "ok"})
        with patch("neo_cortex.mcp._cortex", object()):
            result = await _run_tool("test_tool", fn)
        assert result == {"data": "ok"}
        fn.assert_called_once()

    @pytest.mark.asyncio
    async def test_catches_exception(self):
        from neo_cortex.mcp import _run_tool

        fn = AsyncMock(side_effect=ValueError("boom"))
        with patch("neo_cortex.mcp._cortex", object()):
            result = await _run_tool("test_tool", fn)
        assert "error" in result
        assert "boom" in result["error"]

    @pytest.mark.asyncio
    async def test_logs_to_boot_log(self):
        from neo_cortex.mcp import _run_tool

        fn = AsyncMock(side_effect=RuntimeError("crash"))
        with patch("neo_cortex.mcp._cortex", object()), \
             patch("neo_cortex.mcp._bl") as mock_bl:
            await _run_tool("test_tool", fn)
        # Should log the tool name and the error
        calls = [str(c) for c in mock_bl.call_args_list]
        assert any("test_tool" in c for c in calls)
        assert any("crash" in c for c in calls)
