"""
Tests for Signal Connection functionality.

Tests the ability to connect signals between nodes in Godot scenes.
"""

from pathlib import Path


from godot_mcp.server import node_add, signal_connect, scene_create


class TestConnectSignal:
    """Tests for the signal_connect tool."""

    def test_signal_connect_basic(self, temp_godot_project: Path) -> None:
        """
        Test connecting a signal between two nodes.

        Creates a scene with a Button and a Node2D, then connects
        the Button's pressed signal to a method on the Node2D.
        """
        # Create a scene with a Control root (for UI elements)
        scene_path = "signal_test_scene.tscn"
        create_result = scene_create(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            root_node_type="Control",
        )
        assert "successfully" in create_result.lower() or "created" in create_result.lower(), (
            f"Failed to create scene: {create_result}"
        )

        # Add a Button node as the signal source
        add_result = node_add(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_type="Button",
            node_name="TestButton",
            parent_node_path="root",
        )
        assert "successfully" in add_result.lower() or "added" in add_result.lower(), (
            f"Failed to add Button: {add_result}"
        )

        # Add a Node2D as the signal target
        add_result = node_add(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_type="Node2D",
            node_name="Handler",
            parent_node_path="root",
        )
        assert "successfully" in add_result.lower() or "added" in add_result.lower(), (
            f"Failed to add Handler: {add_result}"
        )

        # Create a script for the handler with the target method
        handler_script = """extends Node2D

func _on_button_pressed():
    print("Button was pressed!")
"""
        script_path = temp_godot_project / "handler.gd"
        script_path.write_text(handler_script, encoding="utf-8")

        # Attach script to handler
        from godot_mcp.server import script_attach

        attach_result = script_attach(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_path="root/Handler",
            script_path="handler.gd",
        )
        assert "successfully" in attach_result.lower() or "attached" in attach_result.lower(), (
            f"Failed to attach script: {attach_result}"
        )

        # Connect the Button's pressed signal to the Handler's method
        result = signal_connect(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            source_node_path="root/TestButton",
            signal_name="pressed",
            target_node_path="root/Handler",
            method_name="_on_button_pressed",
        )

        assert "successfully" in result.lower() or "connected" in result.lower(), (
            f"signal_connect failed: {result}"
        )

        # Verify the connection is in the scene file
        scene_file = temp_godot_project / scene_path
        scene_content = scene_file.read_text(encoding="utf-8")

        # The .tscn file should contain a connection block
        assert "connection" in scene_content.lower() or "signal" in scene_content.lower(), (
            f"Connection not found in scene file. Content:\n{scene_content}"
        )

    def test_signal_connect_invalid_scene(self, temp_godot_project: Path) -> None:
        """Test that connecting signals in non-existent scene fails gracefully."""
        result = signal_connect(
            project_path=str(temp_godot_project),
            scene_path="nonexistent.tscn",
            source_node_path="root/Button",
            signal_name="pressed",
            target_node_path="root/Handler",
            method_name="_on_pressed",
        )

        assert (
            "error" in result.lower() or "not exist" in result.lower() or "failed" in result.lower()
        ), f"Expected error for non-existent scene, got: {result}"

    def test_signal_connect_missing_parameters(self) -> None:
        """Test that missing required parameters are handled."""
        result = signal_connect(
            project_path="",
            scene_path="scene.tscn",
            source_node_path="root/Button",
            signal_name="pressed",
            target_node_path="root/Handler",
            method_name="_on_pressed",
        )
        assert "required" in result.lower() or "invalid" in result.lower(), (
            f"Expected error for empty project_path, got: {result}"
        )

    def test_signal_connect_node2d_signals(self, temp_godot_project: Path) -> None:
        """
        Test connecting Node2D built-in signals.

        Tests connecting visibility_changed signal from one Node2D to another.
        """
        # Create a scene
        scene_path = "node2d_signal_test.tscn"
        scene_create(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            root_node_type="Node2D",
        )

        # Add source node
        node_add(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_type="Node2D",
            node_name="Source",
            parent_node_path="root",
        )

        # Add target node
        node_add(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_type="Node2D",
            node_name="Target",
            parent_node_path="root",
        )

        # Create handler script
        handler_script = """extends Node2D

func _on_visibility_changed():
    print("Visibility changed!")
"""
        script_path = temp_godot_project / "visibility_handler.gd"
        script_path.write_text(handler_script, encoding="utf-8")

        # Attach script
        from godot_mcp.server import script_attach

        script_attach(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            node_path="root/Target",
            script_path="visibility_handler.gd",
        )

        # Connect visibility_changed signal
        result = signal_connect(
            project_path=str(temp_godot_project),
            scene_path=scene_path,
            source_node_path="root/Source",
            signal_name="visibility_changed",
            target_node_path="root/Target",
            method_name="_on_visibility_changed",
        )

        assert "successfully" in result.lower() or "connected" in result.lower(), (
            f"signal_connect failed: {result}"
        )
