"""Tests for collision and physics operations."""

from pathlib import Path

import pytest

from godot_mcp.server import (
    collision_add_shape,
    collision_set_layers,
    physics_set_body_properties,
    scene_create,
    node_add,
)


class TestCollisionAddShape:
    """Test cases for the collision_add_shape tool."""

    def test_add_rectangle_shape_2d(
        self, temp_godot_project: Path
    ) -> None:
        """Test adding a RectangleShape2D to a CollisionObject2D."""
        # Setup: create scene with a StaticBody2D
        scene_path = "test_scene.tscn"
        scene_create(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            root_node_type="Node2D",
        )
        node_add(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            parent_node_path=".",
            node_type="StaticBody2D",
            node_name="StaticBody",
        )

        # Add collision shape
        result = collision_add_shape(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_path="StaticBody",
            shape_type="RectangleShape2D",
            shape_properties='{"size": [20, 30]}',
        )

        assert "successfully" in result.lower() or "added" in result.lower()
        assert "RectangleShape2D" in result

    def test_add_circle_shape_2d(
        self, temp_godot_project: Path
    ) -> None:
        """Test adding a CircleShape2D."""
        scene_path = "test_scene.tscn"
        scene_create(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            root_node_type="Node2D",
        )
        node_add(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            parent_node_path=".",
            node_type="Area2D",
            node_name="Area",
        )

        result = collision_add_shape(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_path="Area",
            shape_type="CircleShape2D",
            shape_properties='{"radius": 15}',
        )

        assert "successfully" in result.lower() or "added" in result.lower()

    def test_add_shape_invalid_node(
        self, temp_godot_project: Path
    ) -> None:
        """Test error handling for non-CollisionObject node."""
        scene_path = "test_scene.tscn"
        scene_create(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            root_node_type="Node2D",
        )

        result = collision_add_shape(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_path=".",  # Root node is Node2D, not CollisionObject
            shape_type="RectangleShape2D",
        )

        assert "not a CollisionObject" in result or "error" in result.lower()

    def test_add_shape_nonexistent_node(
        self, temp_godot_project: Path
    ) -> None:
        """Test error handling for nonexistent node."""
        scene_path = "test_scene.tscn"
        scene_create(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
        )

        result = collision_add_shape(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_path="NonexistentNode",
            shape_type="RectangleShape2D",
        )

        assert "not found" in result.lower() or "error" in result.lower()


class TestCollisionSetLayers:
    """Test cases for the collision_set_layers tool."""

    def test_set_collision_layers(
        self, temp_godot_project: Path
    ) -> None:
        """Test setting collision layers and masks."""
        scene_path = "test_scene.tscn"
        scene_create(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            root_node_type="Node2D",
        )
        node_add(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            parent_node_path=".",
            node_type="RigidBody2D",
            node_name="RigidBody",
        )

        result = collision_set_layers(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_path="RigidBody",
            collision_layer=1,  # Layer 1
            collision_mask=2,   # Can collide with layer 2
        )

        assert "successfully" in result.lower() or "configured" in result.lower()

    def test_set_collision_layers_missing_params(
        self, temp_godot_project: Path
    ) -> None:
        """Test error handling when no layer/mask specified."""
        scene_path = "test_scene.tscn"
        scene_create(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
        )
        node_add(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            parent_node_path=".",
            node_type="StaticBody2D",
            node_name="Static",
        )

        result = collision_set_layers(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_path="Static",
        )

        assert "must be specified" in result or "error" in result.lower()


class TestPhysicsSetBodyProperties:
    """Test cases for the physics_set_body_properties tool."""

    def test_set_body_properties(
        self, temp_godot_project: Path
    ) -> None:
        """Test setting physics body properties."""
        scene_path = "test_scene.tscn"
        scene_create(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            root_node_type="Node2D",
        )
        node_add(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            parent_node_path=".",
            node_type="RigidBody2D",
            node_name="RigidBody",
        )

        result = physics_set_body_properties(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_path="RigidBody",
            mass=10.0,
            friction=0.5,
            bounce=0.3,
        )

        assert "successfully" in result.lower() or "set" in result.lower()
        assert "mass=10" in result or "10.0" in result

    def test_set_body_properties_gravity_scale(
        self, temp_godot_project: Path
    ) -> None:
        """Test setting gravity scale."""
        scene_path = "test_scene.tscn"
        scene_create(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            root_node_type="Node2D",
        )
        node_add(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            parent_node_path=".",
            node_type="RigidBody2D",
            node_name="RigidBody",
        )

        result = physics_set_body_properties(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_path="RigidBody",
            gravity_scale=2.0,
        )

        assert "successfully" in result.lower() or "set" in result.lower()

    def test_set_body_properties_invalid_node(
        self, temp_godot_project: Path
    ) -> None:
        """Test error handling for non-RigidBody node."""
        scene_path = "test_scene.tscn"
        scene_create(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            root_node_type="Node2D",
        )
        node_add(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            parent_node_path=".",
            node_type="StaticBody2D",  # Not a RigidBody
            node_name="Static",
        )

        result = physics_set_body_properties(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_path="Static",
            mass=5.0,
        )

        assert "not a RigidBody" in result or "error" in result.lower()

    def test_set_body_properties_missing_params(
        self, temp_godot_project: Path
    ) -> None:
        """Test error handling when no properties specified."""
        scene_path = "test_scene.tscn"
        scene_create(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
        )
        node_add(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            parent_node_path=".",
            node_type="RigidBody2D",
            node_name="RigidBody",
        )

        result = physics_set_body_properties(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_path="RigidBody",
        )

        assert "must be specified" in result or "error" in result.lower()
