"""
Integration tests for Material operations.

Tests the material creation and reading features:
- resource_create_material: Create material resources
- resource_get_material_properties: Read material properties
"""

import json
from pathlib import Path

import pytest

from godot_mcp.server import (
    GodotServer,
    node_add,
    resource_create_material,
    scene_create,
    resource_get_material_properties,
)


class TestCreateMaterial:
    """Tests for the resource_create_material tool."""

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

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

        # Verify the material file was created
        material_path = temp_godot_project / "materials" / "red.tres"
        assert material_path.exists()

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

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

        # Verify the material file was created
        material_path = temp_godot_project / "materials" / "metal.tres"
        assert material_path.exists()

    def test_resource_create_material_with_emission(
        self, temp_godot_project: Path, godot_client: GodotServer
    ) -> None:
        """Test creating a material with emission enabled."""
        result = resource_create_material(
            project_path=str(temp_godot_project),
            save_path="materials/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_named_color(
        self, temp_godot_project: Path, godot_client: GodotServer
    ) -> None:
        """Test creating a material using a named color."""
        result = resource_create_material(
            project_path=str(temp_godot_project),
            save_path="materials/blue.tres",
            albedo_color="blue",
        )

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

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

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

    @pytest.fixture
    def temp_3d_scene(self, temp_godot_project: Path) -> Path:
        """Create a temporary 3D scene with a MeshInstance3D node."""
        # Create a 3D scene
        scene_create(
            project_path=str(temp_godot_project),
            scene_path="3d_test.tscn",
            root_node_type="Node3D",
        )

        # Add a MeshInstance3D node
        node_add(
            project_path=str(temp_godot_project),
            scene_path="3d_test.tscn",
            node_type="MeshInstance3D",
            node_name="Cube",
            parent_node_path="root",
        )

        return Path("3d_test.tscn")

    def test_resource_create_material_and_assign(
        self,
        temp_godot_project: Path,
        temp_3d_scene: Path,
        godot_client: GodotServer,
    ) -> None:
        """Test creating a material and assigning it to a node."""
        result = resource_create_material(
            project_path=str(temp_godot_project),
            save_path="materials/assigned.tres",
            albedo_color="#FF00FF",
            scene_path=str(temp_3d_scene),
            target_node_path="root/Cube",
        )

        # The material should be created and assigned
        assert "material" in result.lower()

    def test_resource_create_material_invalid_project(self) -> None:
        """Test that invalid project paths are rejected."""
        result = resource_create_material(
            project_path="/nonexistent/path",
            save_path="materials/test.tres",
            albedo_color="#FF0000",
        )

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


class TestGetMaterialProperties:
    """Tests for the resource_get_material_properties tool (Read operation)."""

    def test_resource_get_material_properties_basic(
        self, temp_godot_project: Path, godot_client: GodotServer
    ) -> None:
        """Test getting properties from a basic material."""
        # First create a material
        resource_create_material(
            project_path=str(temp_godot_project),
            save_path="materials/test_read.tres",
            albedo_color="#FF0000",
            metallic=0.5,
            roughness=0.3,
        )

        # Now read its properties
        result = resource_get_material_properties(
            project_path=str(temp_godot_project),
            material_path="materials/test_read.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

        # Check values
        assert abs(props["metallic"] - 0.5) < 0.01
        assert abs(props["roughness"] - 0.3) < 0.01

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

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

        data = json.loads(result)
        props = data["properties"]

        assert props["emission_enabled"] is True
        assert "emission" in props
        assert "emission_energy_multiplier" in props

    def test_resource_get_material_properties_hex_color(
        self, temp_godot_project: Path, godot_client: GodotServer
    ) -> None:
        """Test that hex color is returned correctly."""
        resource_create_material(
            project_path=str(temp_godot_project),
            save_path="materials/test_hex.tres",
            albedo_color="#3498DB",
        )

        result = resource_get_material_properties(
            project_path=str(temp_godot_project),
            material_path="materials/test_hex.tres",
        )

        data = json.loads(result)
        props = data["properties"]

        # Should have hex color representation
        assert "albedo_color_hex" in props
        # The hex should contain the color value (case-insensitive comparison)
        assert "3498db" in props["albedo_color_hex"].lower()

    def test_resource_get_material_properties_invalid_path(self, temp_godot_project: Path) -> None:
        """Test that invalid material paths are rejected."""
        result = resource_get_material_properties(
            project_path=str(temp_godot_project),
            material_path="materials/nonexistent.tres",
        )
        assert "error" in result.lower() or "not exist" in result.lower()


class TestIntegrationWorkflow:
    """Integration tests that combine multiple features."""

    def test_complete_game_setup_workflow(
        self, temp_godot_project: Path, godot_client: GodotServer
    ) -> None:
        """Test a complete game setup workflow using material features."""
        from godot_mcp.server import input_setup_action

        # Step 1: Set up input controls
        setup_result = input_setup_action(
            project_path=str(temp_godot_project),
            action_name="player_jump",
            keys=["Space", "W"],
        )
        assert "fail" not in setup_result.lower() or "error" not in setup_result.lower()

        # Step 2: Create a 3D scene
        scene_result = scene_create(
            project_path=str(temp_godot_project),
            scene_path="game_level.tscn",
            root_node_type="Node3D",
        )
        assert "successfully" in scene_result.lower()

        # Step 3: Add a mesh for the player
        node_add(
            project_path=str(temp_godot_project),
            scene_path="game_level.tscn",
            node_type="MeshInstance3D",
            node_name="Player",
            parent_node_path="root",
        )

        # Step 4: Create and assign a material to the player
        material_result = resource_create_material(
            project_path=str(temp_godot_project),
            save_path="materials/player.tres",
            albedo_color="#3498db",
            metallic=0.3,
            roughness=0.7,
            scene_path="game_level.tscn",
            target_node_path="root/Player",
        )
        assert "material" in material_result.lower()

        # Verify all files were created
        assert (temp_godot_project / "game_level.tscn").exists()
        assert (temp_godot_project / "materials" / "player.tres").exists()
