"""
E2E tests for Material operations.

Tests material creation and reading using real Godot demo projects:
- resource_create_material
- resource_get_material_properties
"""

import json
from pathlib import Path


from godot_mcp.server import (
    node_add,
    resource_create_material,
    scene_create,
    resource_get_material_properties,
    input_list_actions,
    tilemap_set_cell,
    input_setup_action,
)


class TestCreateMaterial:
    """E2E tests for resource_create_material tool."""

    def test_create_basic_material(self, demo_project_copy: Path) -> None:
        """Test creating a basic material with albedo color."""
        result = resource_create_material(
            project_path=str(demo_project_copy),
            save_path="materials/e2e_red.tres",
            albedo_color="#FF0000",
        )

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

        # Verify material file was created
        material_path = demo_project_copy / "materials" / "e2e_red.tres"
        assert material_path.exists()

    def test_resource_create_material_with_properties(self, demo_project_copy: Path) -> None:
        """Test creating a material with multiple properties."""
        result = resource_create_material(
            project_path=str(demo_project_copy),
            save_path="materials/e2e_metal.tres",
            albedo_color="#888888",
            metallic=1.0,
            roughness=0.2,
        )

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

    def test_resource_create_material_with_emission(self, demo_project_copy: Path) -> None:
        """Test creating a material with emission enabled."""
        result = resource_create_material(
            project_path=str(demo_project_copy),
            save_path="materials/e2e_glow.tres",
            albedo_color="#00FF00",
            emission_enabled=True,
            emission_color="#00FF00",
            emission_energy=2.0,
        )

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

    def test_resource_create_material_with_transparency(self, demo_project_copy: Path) -> None:
        """Test creating a material with transparency."""
        result = resource_create_material(
            project_path=str(demo_project_copy),
            save_path="materials/e2e_glass.tres",
            albedo_color="#FFFFFF80",
            transparency="alpha",
        )

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

    def test_resource_create_material_and_assign(self, demo_project_copy: Path) -> None:
        """Test creating a material and assigning to a 3D node."""
        # Create a 3D scene
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_material_scene.tscn",
            root_node_type="Node3D",
        )
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_material_scene.tscn",
            node_type="MeshInstance3D",
            node_name="Cube",
            parent_node_path="root",
        )

        result = resource_create_material(
            project_path=str(demo_project_copy),
            save_path="materials/e2e_assigned.tres",
            albedo_color="#FF00FF",
            scene_path="e2e_material_scene.tscn",
            target_node_path="root/Cube",
        )

        assert "material" in result.lower()


class TestGetMaterialProperties:
    """E2E tests for resource_get_material_properties tool."""

    def test_resource_get_material_properties_basic(self, demo_project_copy: Path) -> None:
        """Test getting properties from a basic material."""
        # Create a material first
        resource_create_material(
            project_path=str(demo_project_copy),
            save_path="materials/e2e_read_test.tres",
            albedo_color="#FF0000",
            metallic=0.5,
            roughness=0.3,
        )

        # Read its properties
        result = resource_get_material_properties(
            project_path=str(demo_project_copy),
            material_path="materials/e2e_read_test.tres",
        )

        data = json.loads(result)
        assert "path" in data
        assert "type" in data
        assert "properties" in data

        props = data["properties"]
        assert "albedo_color" in props
        assert "metallic" in props
        assert "roughness" in props

    def test_resource_get_material_properties_with_emission(self, demo_project_copy: Path) -> None:
        """Test getting properties from a material with emission."""
        resource_create_material(
            project_path=str(demo_project_copy),
            save_path="materials/e2e_emission_read.tres",
            albedo_color="#00FF00",
            emission_enabled=True,
            emission_color="#00FF00",
            emission_energy=2.0,
        )

        result = resource_get_material_properties(
            project_path=str(demo_project_copy),
            material_path="materials/e2e_emission_read.tres",
        )

        data = json.loads(result)
        props = data["properties"]
        assert props["emission_enabled"] is True

    def test_resource_get_material_properties_invalid_path(self, demo_project_copy: Path) -> None:
        """Test resource_get_material_properties with invalid path."""
        result = resource_get_material_properties(
            project_path=str(demo_project_copy),
            material_path="materials/nonexistent.tres",
        )

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


class TestInputTilemapMaterialWorkflow:
    """Integration tests combining input, tilemap, and material features."""

    def test_complete_game_setup_workflow(self, demo_project_copy: Path) -> None:
        """Test a complete game setup workflow using all features."""
        # Step 1: Set up input controls
        movement_actions = [
            ("game_up", ["W", "Up"]),
            ("game_down", ["S", "Down"]),
            ("game_left", ["A", "Left"]),
            ("game_right", ["D", "Right"]),
            ("game_jump", ["Space"]),
            ("game_action", ["E", "Enter"]),
        ]

        for action_name, keys in movement_actions:
            result = input_setup_action(
                project_path=str(demo_project_copy),
                action_name=action_name,
                keys=keys,
            )
            assert "error" not in result.lower()

        # Step 2: Create a 2D game level with TileMap
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="levels/level_1.tscn",
            root_node_type="Node2D",
        )
        node_add(
            project_path=str(demo_project_copy),
            scene_path="levels/level_1.tscn",
            node_type="TileMap",
            node_name="LevelTileMap",
            parent_node_path="root",
        )

        # Set some tilemap cells (would need tileset for full functionality)
        for x in range(10):
            tilemap_set_cell(
                project_path=str(demo_project_copy),
                scene_path="levels/level_1.tscn",
                node_path="root/LevelTileMap",
                x=x,
                y=5,
                source_id=0,
            )

        # Step 3: Create a 3D scene with materials
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="3d_level.tscn",
            root_node_type="Node3D",
        )
        node_add(
            project_path=str(demo_project_copy),
            scene_path="3d_level.tscn",
            node_type="MeshInstance3D",
            node_name="Ground",
            parent_node_path="root",
        )
        node_add(
            project_path=str(demo_project_copy),
            scene_path="3d_level.tscn",
            node_type="MeshInstance3D",
            node_name="Player",
            parent_node_path="root",
        )

        # Create materials for 3D objects
        resource_create_material(
            project_path=str(demo_project_copy),
            save_path="materials/ground.tres",
            albedo_color="#228B22",
            roughness=0.8,
        )
        resource_create_material(
            project_path=str(demo_project_copy),
            save_path="materials/player.tres",
            albedo_color="#3498db",
            metallic=0.3,
            roughness=0.5,
        )

        # Step 4: Verify files were created
        assert (demo_project_copy / "levels" / "level_1.tscn").exists()
        assert (demo_project_copy / "3d_level.tscn").exists()
        assert (demo_project_copy / "materials" / "ground.tres").exists()
        assert (demo_project_copy / "materials" / "player.tres").exists()

        # Step 5: List input actions to verify
        actions_result = input_list_actions(
            project_path=str(demo_project_copy),
        )
        if "error" not in actions_result.lower():
            # Should contain our game actions
            project_content = (demo_project_copy / "project.godot").read_text()
            assert "game_jump" in project_content
            assert "game_action" in project_content
