"""Tests for exec tool with editor context."""

import pytest
from unittest.mock import AsyncMock, patch

from godotiq.tools.bridge.exec_code import exec_code


class TestExecEditorContext:
    @pytest.mark.asyncio
    async def test_default_context_is_game(self):
        """Default context should be 'game' for backward compatibility."""
        mock_bridge = AsyncMock()
        mock_bridge.request = AsyncMock(return_value={
            "status": "OK", "result": "42", "error": "",
        })
        with patch("godotiq.tools.bridge.exec_code.get_bridge", return_value=mock_bridge):
            await exec_code(code="func run():\n\treturn 42")
            call_args = mock_bridge.request.call_args
            assert call_args[0][0] == "exec"

    @pytest.mark.asyncio
    async def test_editor_context_explicit(self):
        """Editor context should send 'exec_editor' to bridge."""
        mock_bridge = AsyncMock()
        mock_bridge.request = AsyncMock(return_value={
            "status": "OK", "result": "Main", "error": "",
        })
        with patch("godotiq.tools.bridge.exec_code.get_bridge", return_value=mock_bridge):
            result = await exec_code(
                code="func run():\n\treturn get_tree().edited_scene_root.name",
                context="editor",
            )
            assert result["status"] == "OK"
            call_args = mock_bridge.request.call_args
            assert call_args[0][0] == "exec_editor"

    @pytest.mark.asyncio
    async def test_game_context_uses_exec_method(self):
        """Game context should use 'exec' method (game-side)."""
        mock_bridge = AsyncMock()
        mock_bridge.request = AsyncMock(return_value={
            "status": "OK", "result": "60", "error": "",
        })
        with patch("godotiq.tools.bridge.exec_code.get_bridge", return_value=mock_bridge):
            await exec_code(
                code="func run():\n\treturn Engine.get_frames_per_second()",
                context="game",
            )
            call_args = mock_bridge.request.call_args
            assert call_args[0][0] == "exec"

    @pytest.mark.asyncio
    async def test_invalid_context(self):
        """Invalid context should return error without bridge call."""
        result = await exec_code(code="func run():\n\treturn 1", context="invalid")
        assert result["status"] == "ERROR"
        assert "Invalid context" in result["error"]

    @pytest.mark.asyncio
    async def test_empty_code_still_errors(self):
        """Empty code should return error regardless of context."""
        result = await exec_code(code="", context="editor")
        assert result["status"] == "ERROR"
        assert "No code" in result["error"]

    @pytest.mark.asyncio
    async def test_editor_context_passes_timeout(self):
        """Editor context should pass timeout_ms in params."""
        mock_bridge = AsyncMock()
        mock_bridge.request = AsyncMock(return_value={
            "status": "OK", "result": "42", "error": "",
        })
        with patch("godotiq.tools.bridge.exec_code.get_bridge", return_value=mock_bridge):
            await exec_code(code="func run():\n\treturn 42", context="editor", timeout_ms=3000)
            call_args = mock_bridge.request.call_args
            params = call_args[1].get("params", call_args[0][1] if len(call_args[0]) > 1 else {})
            assert params["timeout_ms"] == 3000

    @pytest.mark.asyncio
    async def test_game_context_passes_timeout(self):
        """Game context should pass timeout_ms in params (unchanged)."""
        mock_bridge = AsyncMock()
        mock_bridge.request = AsyncMock(return_value={
            "status": "OK", "result": "42", "error": "",
        })
        with patch("godotiq.tools.bridge.exec_code.get_bridge", return_value=mock_bridge):
            await exec_code(code="func run():\n\treturn 42", context="game", timeout_ms=7000)
            call_args = mock_bridge.request.call_args
            params = call_args[1].get("params", call_args[0][1] if len(call_args[0]) > 1 else {})
            assert params["timeout_ms"] == 7000
