"""
测试 react_loop.py —— _execute_action_internal 工具执行与错误处理

遵从 fastclaw 风格：框架不包裹外层超时，工具自行管理超时。
"""
import asyncio
import sys
import tempfile
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent.parent))

import pytest
from aacode.core.react_loop import AsyncReActLoop
from aacode.utils.context_manager import ContextManager
from aacode.utils.tool_registry import get_global_registry, ToolSchema, ToolParameter


@pytest.fixture
def react_loop():
    with tempfile.TemporaryDirectory() as td:
        project_path = Path(td)
        cm = ContextManager(project_path)

        async def dummy_caller(messages):
            return "Task done"

        tools = {}
        loop = AsyncReActLoop(
            model_caller=dummy_caller,
            tools=tools,
            context_manager=cm,
            max_iterations=50,
            project_path=project_path,
        )
        yield loop


@pytest.fixture
def fast_tool():
    """快速工具，无超时，用于验证框架直接透传调用"""
    registry = get_global_registry()

    async def _fast(**kwargs):
        return "executed"

    schema = ToolSchema(
        name="fast_tool",
        description="A fast tool",
        parameters=[],
    )
    registry.register(_fast, schema)
    return _fast, schema


class TestExecuteActionInternal:
    """_execute_action_internal 基本执行流"""

    @pytest.mark.asyncio
    async def test_tool_executed_successfully(self, react_loop, fast_tool):
        """工具正常执行并返回结果"""
        tool_func, schema = fast_tool
        react_loop.tools["fast_tool"] = tool_func
        registry = get_global_registry()
        registry.register(tool_func, schema)

        result = await react_loop._execute_action_internal("fast_tool", {})
        assert "executed" in result

    @pytest.mark.asyncio
    async def test_tool_not_found_returns_error(self, react_loop):
        result = await react_loop._execute_action_internal(
            "nonexistent_tool", {}
        )
        assert "not found" in result.lower() or "unknown" in result.lower()

    @pytest.mark.asyncio
    async def test_parameter_error_detected(self, react_loop, fast_tool):
        tool_func, schema = fast_tool
        react_loop.tools["fast_tool"] = tool_func
        registry = get_global_registry()
        registry.register(tool_func, schema)

        result = await react_loop._execute_action_internal(
            "fast_tool", {"_error": "bad json", "_raw": "invalid"}
        )
        assert "Parameter parsing error" in result

    @pytest.mark.asyncio
    async def test_tool_returning_dict_is_processed(self, react_loop):
        """工具返回 dict 时被正确处理"""
        registry = get_global_registry()

        async def _dict_tool(**kwargs):
            return {"key": "value"}

        schema = ToolSchema(
            name="dict_tool",
            description="Returns dict",
            parameters=[],
        )
        registry.register(_dict_tool, schema)
        react_loop.tools["dict_tool"] = _dict_tool

        result = await react_loop._execute_action_internal("dict_tool", {})
        assert "key" in result
        assert "value" in result

    @pytest.mark.asyncio
    async def test_tool_returning_none_is_handled(self, react_loop):
        """工具返回 None 时返回友好消息"""
        registry = get_global_registry()

        async def _none_tool(**kwargs):
            return None

        schema = ToolSchema(
            name="none_tool",
            description="Returns None",
            parameters=[],
        )
        registry.register(_none_tool, schema)
        react_loop.tools["none_tool"] = _none_tool

        result = await react_loop._execute_action_internal("none_tool", {})
        assert "no return value" in result.lower()
