"""Tests for camera control tool."""

import pytest
from unittest.mock import AsyncMock, patch

from godotiq.tools.bridge.camera import camera


class TestCameraTool:
    @pytest.mark.asyncio
    async def test_get_position(self):
        """get_position returns camera state."""
        mock_bridge = AsyncMock()
        mock_bridge.request = AsyncMock(return_value={
            "action": "get_position",
            "position": [1.5, 3.0, 5.2],
            "rotation_degrees": [-20.0, 45.0, 0.0],
            "forward": [0.5, -0.3, -0.7],
            "fov": 70.0,
        })
        with patch("godotiq.tools.bridge.camera.get_bridge", return_value=mock_bridge):
            result = await camera(action="get_position")
            assert result["position"] == [1.5, 3.0, 5.2]
            assert result["fov"] == 70.0

    @pytest.mark.asyncio
    async def test_look_at(self):
        """look_at sends position and target to bridge."""
        mock_bridge = AsyncMock()
        mock_bridge.request = AsyncMock(return_value={
            "action": "look_at",
            "position": [5, 3, 5],
            "rotation_degrees": [-20.0, 45.0, 0.0],
            "note": "Camera position is temporary",
        })
        with patch("godotiq.tools.bridge.camera.get_bridge", return_value=mock_bridge):
            result = await camera(
                action="look_at",
                position=[5, 3, 5],
                target=[0, 0, 0],
            )
            assert result["action"] == "look_at"
            params = mock_bridge.request.call_args[1]["params"]
            assert params["position"] == [5, 3, 5]
            assert params["target"] == [0, 0, 0]

    @pytest.mark.asyncio
    async def test_look_at_missing_position(self):
        """look_at without position returns error."""
        result = await camera(action="look_at")
        assert "error" in result

    @pytest.mark.asyncio
    async def test_look_at_position_validation(self):
        """look_at with wrong-length position returns error."""
        result = await camera(action="look_at", position=[1, 2])
        assert "error" in result
        assert "3 elements" in result["error"]

    @pytest.mark.asyncio
    async def test_look_at_target_validation(self):
        """look_at with wrong-length target returns error."""
        result = await camera(action="look_at", position=[1, 2, 3], target=[1])
        assert "error" in result
        assert "3 elements" in result["error"]

    @pytest.mark.asyncio
    async def test_focus_node(self):
        """focus_node sends node name to bridge."""
        mock_bridge = AsyncMock()
        mock_bridge.request = AsyncMock(return_value={
            "action": "focus_node",
            "node": "StorageShelf",
            "node_position": [1.2, 0, -0.5],
            "selected": True,
        })
        with patch("godotiq.tools.bridge.camera.get_bridge", return_value=mock_bridge):
            result = await camera(action="focus_node", node="StorageShelf")
            assert result["selected"] is True
            assert result["node"] == "StorageShelf"

    @pytest.mark.asyncio
    async def test_focus_node_missing_name(self):
        """focus_node without node name returns error."""
        result = await camera(action="focus_node")
        assert "error" in result

    @pytest.mark.asyncio
    async def test_default_action(self):
        """Default action is get_position."""
        mock_bridge = AsyncMock()
        mock_bridge.request = AsyncMock(return_value={"action": "get_position"})
        with patch("godotiq.tools.bridge.camera.get_bridge", return_value=mock_bridge):
            await camera()
            params = mock_bridge.request.call_args[1]["params"]
            assert params["action"] == "get_position"

    @pytest.mark.asyncio
    async def test_look_at_without_target(self):
        """look_at with position only omits target from params."""
        mock_bridge = AsyncMock()
        mock_bridge.request = AsyncMock(return_value={"action": "look_at"})
        with patch("godotiq.tools.bridge.camera.get_bridge", return_value=mock_bridge):
            await camera(action="look_at", position=[5, 3, 5])
            params = mock_bridge.request.call_args[1]["params"]
            assert params["position"] == [5, 3, 5]
            assert "target" not in params
