"""
E2E tests for Scene and Node operations.

Tests scene and node manipulation tools using real Godot demo projects:
- scene_create
- node_add
- scene_save
- node_load_sprite_texture
- resource_get_uid
- project_update_uids
"""

from pathlib import Path


from godot_mcp.server import (
    node_add,
    scene_create,
    resource_get_uid,
    node_load_sprite_texture,
    scene_save,
    project_update_uids,
)


class TestCreateScene:
    """E2E tests for scene_create tool."""

    def test_create_2d_scene_in_demo(self, demo_project_copy: Path) -> None:
        """Test creating a new 2D scene in a demo project."""
        result = scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_test_scene.tscn",
            root_node_type="Node2D",
        )

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

        # Verify scene file was created
        scene_file = demo_project_copy / "e2e_test_scene.tscn"
        assert scene_file.exists()

    def test_create_3d_scene_in_demo(self, demo_project_copy: Path) -> None:
        """Test creating a new 3D scene in a demo project."""
        result = scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_test_3d.tscn",
            root_node_type="Node3D",
        )

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

        scene_file = demo_project_copy / "e2e_test_3d.tscn"
        assert scene_file.exists()

    def test_create_ui_scene(self, demo_project_copy: Path) -> None:
        """Test creating a UI scene with Control root."""
        result = scene_create(
            project_path=str(demo_project_copy),
            scene_path="ui/e2e_menu.tscn",
            root_node_type="Control",
        )

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

    def test_scene_create_in_subdirectory(self, demo_project_copy: Path) -> None:
        """Test creating a scene in a subdirectory."""
        result = scene_create(
            project_path=str(demo_project_copy),
            scene_path="levels/e2e_level.tscn",
            root_node_type="Node2D",
        )

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


class TestAddNode:
    """E2E tests for node_add tool."""

    def test_node_add_to_new_scene(self, demo_project_copy: Path) -> None:
        """Test adding a node to a newly created scene."""
        # First create a scene
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_node_add_test.tscn",
            root_node_type="Node2D",
        )

        # Add a child node
        result = node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_node_add_test.tscn",
            node_type="Sprite2D",
            node_name="TestSprite",
            parent_node_path="root",
        )

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

    def test_add_multiple_nodes(self, demo_project_copy: Path) -> None:
        """Test adding multiple nodes to a scene."""
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_multi_node.tscn",
            root_node_type="Node2D",
        )

        # Add several nodes
        nodes_to_add = [
            ("Sprite2D", "Player"),
            ("Camera2D", "MainCamera"),
            ("CanvasLayer", "UI"),
        ]

        for node_type, node_name in nodes_to_add:
            result = node_add(
                project_path=str(demo_project_copy),
                scene_path="e2e_multi_node.tscn",
                node_type=node_type,
                node_name=node_name,
                parent_node_path="root",
            )
            assert "error" not in result.lower(), f"Failed to add {node_name}"

    def test_add_nested_nodes(self, demo_project_copy: Path) -> None:
        """Test adding nested nodes (child of child)."""
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_nested.tscn",
            root_node_type="Node2D",
        )

        # Add parent node
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_nested.tscn",
            node_type="Node2D",
            node_name="Parent",
            parent_node_path="root",
        )

        # Add child of child
        result = node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_nested.tscn",
            node_type="Sprite2D",
            node_name="Child",
            parent_node_path="root/Parent",
        )

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

    def test_add_3d_nodes(self, demo_project_copy: Path) -> None:
        """Test adding 3D nodes to a 3D scene."""
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_3d_nodes.tscn",
            root_node_type="Node3D",
        )

        # Add 3D nodes
        nodes_to_add = [
            ("MeshInstance3D", "Mesh"),
            ("Camera3D", "MainCamera"),
            ("DirectionalLight3D", "Sun"),
        ]

        for node_type, node_name in nodes_to_add:
            result = node_add(
                project_path=str(demo_project_copy),
                scene_path="e2e_3d_nodes.tscn",
                node_type=node_type,
                node_name=node_name,
                parent_node_path="root",
            )
            assert "error" not in result.lower(), f"Failed to add {node_name}"


class TestSaveScene:
    """E2E tests for scene_save tool."""

    def test_scene_save_to_new_path(self, demo_project_copy: Path) -> None:
        """Test saving a scene to a new path."""
        # Create a scene
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_save_test.tscn",
            root_node_type="Node2D",
        )

        # Save to a new path
        result = scene_save(
            project_path=str(demo_project_copy),
            scene_path="e2e_save_test.tscn",
            new_path="e2e_save_test_copy.tscn",
        )

        # Should succeed or indicate save
        assert isinstance(result, str)

    def test_save_modified_scene(self, demo_project_copy: Path) -> None:
        """Test saving a scene after adding nodes."""
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_modify_save.tscn",
            root_node_type="Node2D",
        )

        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_modify_save.tscn",
            node_type="Sprite2D",
            node_name="TestSprite",
            parent_node_path="root",
        )

        result = scene_save(
            project_path=str(demo_project_copy),
            scene_path="e2e_modify_save.tscn",
        )

        assert isinstance(result, str)


class TestLoadSprite:
    """E2E tests for node_load_sprite_texture tool."""

    def test_node_load_sprite_texture_invalid_texture(self, demo_project_copy: Path) -> None:
        """Test node_load_sprite_texture with non-existent texture."""
        # Create a scene with a Sprite2D
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_sprite_test.tscn",
            root_node_type="Node2D",
        )
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_sprite_test.tscn",
            node_type="Sprite2D",
            node_name="TestSprite",
            parent_node_path="root",
        )

        # Try to load non-existent texture
        result = node_load_sprite_texture(
            project_path=str(demo_project_copy),
            scene_path="e2e_sprite_test.tscn",
            node_path="root/TestSprite",
            texture_path="nonexistent.png",
        )

        # Should handle error gracefully
        assert isinstance(result, str)


class TestGetUid:
    """E2E tests for resource_get_uid tool."""

    def test_resource_get_uid_for_scene(self, demo_project_copy: Path) -> None:
        """Test getting UID for a scene file."""
        # Create a scene
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_uid_test.tscn",
            root_node_type="Node2D",
        )

        result = resource_get_uid(
            project_path=str(demo_project_copy),
            file_path="e2e_uid_test.tscn",
        )

        # Should return UID or indicate not available
        assert isinstance(result, str)

    def test_resource_get_uid_nonexistent_file(self, demo_project_copy: Path) -> None:
        """Test resource_get_uid for non-existent file."""
        result = resource_get_uid(
            project_path=str(demo_project_copy),
            file_path="nonexistent.tscn",
        )

        # Should return error
        assert "error" in result.lower() or "not" in result.lower()


class TestUpdateProjectUids:
    """E2E tests for project_update_uids tool."""

    def test_update_uids_on_demo(self, demo_project_copy: Path) -> None:
        """Test updating UIDs in a demo project."""
        result = project_update_uids(
            project_path=str(demo_project_copy),
        )

        # Should complete without error
        assert isinstance(result, str)
        # May indicate success or that it requires Godot 4.4+


class TestSceneWorkflowE2E:
    """Integration tests combining multiple scene operations."""

    def test_complete_scene_creation_workflow(self, demo_project_copy: Path) -> None:
        """Test a complete scene creation workflow."""
        # Step 1: Create a 2D scene
        create_result = scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_complete_workflow.tscn",
            root_node_type="Node2D",
        )
        assert "successfully" in create_result.lower() or "created" in create_result.lower()

        # Step 2: Add player node
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_complete_workflow.tscn",
            node_type="CharacterBody2D",
            node_name="Player",
            parent_node_path="root",
        )

        # Step 3: Add sprite to player
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_complete_workflow.tscn",
            node_type="Sprite2D",
            node_name="Sprite",
            parent_node_path="root/Player",
        )

        # Step 4: Add collision shape to player
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_complete_workflow.tscn",
            node_type="CollisionShape2D",
            node_name="CollisionShape",
            parent_node_path="root/Player",
        )

        # Step 5: Add camera
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_complete_workflow.tscn",
            node_type="Camera2D",
            node_name="MainCamera",
            parent_node_path="root",
        )

        # Verify scene file has all nodes
        scene_file = demo_project_copy / "e2e_complete_workflow.tscn"
        content = scene_file.read_text(encoding="utf-8")

        assert "Player" in content
        assert "Camera2D" in content
