"""
E2E tests for Signal Connection functionality.

Tests signal-related tools using real Godot demo projects:
- signal_connect
"""

from pathlib import Path


from godot_mcp.server import node_add, script_attach, signal_connect, scene_create


class TestConnectSignal:
    """E2E tests for signal_connect tool."""

    def test_connect_button_pressed_signal(self, demo_project_copy: Path) -> None:
        """Test connecting a Button's pressed signal."""
        # Create a UI scene
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_signal_test.tscn",
            root_node_type="Control",
        )

        # Add a Button
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_signal_test.tscn",
            node_type="Button",
            node_name="TestButton",
            parent_node_path="root",
        )

        # Add a handler node
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_signal_test.tscn",
            node_type="Node",
            node_name="Handler",
            parent_node_path="root",
        )

        # Create handler script
        handler_script = """extends Node

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

        script_attach(
            project_path=str(demo_project_copy),
            scene_path="e2e_signal_test.tscn",
            node_path="root/Handler",
            script_path="e2e_signal_handler.gd",
        )

        # Connect the signal
        result = signal_connect(
            project_path=str(demo_project_copy),
            scene_path="e2e_signal_test.tscn",
            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()

    def test_connect_visibility_changed_signal(self, demo_project_copy: Path) -> None:
        """Test connecting visibility_changed signal between nodes."""
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_visibility_signal.tscn",
            root_node_type="Node2D",
        )

        # Add source node
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_visibility_signal.tscn",
            node_type="Node2D",
            node_name="Source",
            parent_node_path="root",
        )

        # Add target node
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_visibility_signal.tscn",
            node_type="Node2D",
            node_name="Target",
            parent_node_path="root",
        )

        # Create handler script
        handler_script = """extends Node2D

func _on_source_visibility_changed():
    print("Source visibility changed!")
"""
        script_path = demo_project_copy / "e2e_visibility_handler.gd"
        script_path.write_text(handler_script, encoding="utf-8")

        script_attach(
            project_path=str(demo_project_copy),
            scene_path="e2e_visibility_signal.tscn",
            node_path="root/Target",
            script_path="e2e_visibility_handler.gd",
        )

        result = signal_connect(
            project_path=str(demo_project_copy),
            scene_path="e2e_visibility_signal.tscn",
            source_node_path="root/Source",
            signal_name="visibility_changed",
            target_node_path="root/Target",
            method_name="_on_source_visibility_changed",
        )

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

    def test_connect_area_entered_signal(self, demo_project_copy: Path) -> None:
        """Test connecting Area2D's area_entered signal."""
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_area_signal.tscn",
            root_node_type="Node2D",
        )

        # Add Area2D
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_area_signal.tscn",
            node_type="Area2D",
            node_name="TriggerArea",
            parent_node_path="root",
        )

        # Add handler
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_area_signal.tscn",
            node_type="Node2D",
            node_name="GameManager",
            parent_node_path="root",
        )

        # Create handler script
        handler_script = """extends Node2D

func _on_area_entered(area):
    print("Area entered: ", area.name)
"""
        script_path = demo_project_copy / "e2e_area_handler.gd"
        script_path.write_text(handler_script, encoding="utf-8")

        script_attach(
            project_path=str(demo_project_copy),
            scene_path="e2e_area_signal.tscn",
            node_path="root/GameManager",
            script_path="e2e_area_handler.gd",
        )

        result = signal_connect(
            project_path=str(demo_project_copy),
            scene_path="e2e_area_signal.tscn",
            source_node_path="root/TriggerArea",
            signal_name="area_entered",
            target_node_path="root/GameManager",
            method_name="_on_area_entered",
        )

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

    def test_signal_connect_nonexistent_scene(self, demo_project_copy: Path) -> None:
        """Test that connecting signals in non-existent scene fails gracefully."""
        result = signal_connect(
            project_path=str(demo_project_copy),
            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()


class TestMultipleSignalConnections:
    """E2E tests for multiple signal connections."""

    def test_connect_multiple_signals_same_source(self, demo_project_copy: Path) -> None:
        """Test connecting multiple signals from the same source node."""
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_multi_signal.tscn",
            root_node_type="Control",
        )

        # Add a Button
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_multi_signal.tscn",
            node_type="Button",
            node_name="TestButton",
            parent_node_path="root",
        )

        # Add handler
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_multi_signal.tscn",
            node_type="Node",
            node_name="Handler",
            parent_node_path="root",
        )

        # Create handler script with multiple methods
        handler_script = """extends Node

func _on_button_pressed():
    print("Button pressed!")

func _on_button_mouse_entered():
    print("Mouse entered button!")

func _on_button_mouse_exited():
    print("Mouse exited button!")
"""
        script_path = demo_project_copy / "e2e_multi_signal_handler.gd"
        script_path.write_text(handler_script, encoding="utf-8")

        script_attach(
            project_path=str(demo_project_copy),
            scene_path="e2e_multi_signal.tscn",
            node_path="root/Handler",
            script_path="e2e_multi_signal_handler.gd",
        )

        # Connect multiple signals
        signals_to_connect = [
            ("pressed", "_on_button_pressed"),
            ("mouse_entered", "_on_button_mouse_entered"),
            ("mouse_exited", "_on_button_mouse_exited"),
        ]

        for signal_name, method_name in signals_to_connect:
            result = signal_connect(
                project_path=str(demo_project_copy),
                scene_path="e2e_multi_signal.tscn",
                source_node_path="root/TestButton",
                signal_name=signal_name,
                target_node_path="root/Handler",
                method_name=method_name,
            )
            assert "error" not in result.lower(), f"Failed to connect {signal_name}"

    def test_signal_connects_different_sources(self, demo_project_copy: Path) -> None:
        """Test connecting signals from different source nodes to same handler."""
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="e2e_diff_source_signals.tscn",
            root_node_type="Control",
        )

        # Add multiple buttons
        for i in range(3):
            node_add(
                project_path=str(demo_project_copy),
                scene_path="e2e_diff_source_signals.tscn",
                node_type="Button",
                node_name=f"Button{i}",
                parent_node_path="root",
            )

        # Add handler
        node_add(
            project_path=str(demo_project_copy),
            scene_path="e2e_diff_source_signals.tscn",
            node_type="Node",
            node_name="ButtonHandler",
            parent_node_path="root",
        )

        # Create handler script
        handler_script = """extends Node

func _on_button_pressed(button_index: int):
    print("Button ", button_index, " pressed!")
"""
        script_path = demo_project_copy / "e2e_button_handler.gd"
        script_path.write_text(handler_script, encoding="utf-8")

        script_attach(
            project_path=str(demo_project_copy),
            scene_path="e2e_diff_source_signals.tscn",
            node_path="root/ButtonHandler",
            script_path="e2e_button_handler.gd",
        )

        # Connect all buttons to handler
        for i in range(3):
            result = signal_connect(
                project_path=str(demo_project_copy),
                scene_path="e2e_diff_source_signals.tscn",
                source_node_path=f"root/Button{i}",
                signal_name="pressed",
                target_node_path="root/ButtonHandler",
                method_name="_on_button_pressed",
            )
            assert "error" not in result.lower(), f"Failed to connect Button{i}"


class TestSignalWorkflow:
    """Integration tests for signal connection workflows."""

    def test_complete_ui_workflow_with_signals(self, demo_project_copy: Path) -> None:
        """Test a complete UI setup with signal connections."""
        # Step 1: Create main menu scene
        scene_create(
            project_path=str(demo_project_copy),
            scene_path="ui/main_menu.tscn",
            root_node_type="Control",
        )

        # Step 2: Add UI elements
        ui_elements = [
            ("VBoxContainer", "MenuContainer"),
            ("Label", "TitleLabel"),
            ("Button", "StartButton"),
            ("Button", "OptionsButton"),
            ("Button", "QuitButton"),
        ]

        parent = "root"
        for node_type, node_name in ui_elements:
            node_add(
                project_path=str(demo_project_copy),
                scene_path="ui/main_menu.tscn",
                node_type=node_type,
                node_name=node_name,
                parent_node_path=parent,
            )
            if node_name == "MenuContainer":
                parent = "root/MenuContainer"

        # Step 3: Create menu controller script
        menu_script = """extends Control

func _on_start_pressed():
    print("Starting game...")
    # get_tree().change_scene_to_file("res://scenes/game.tscn")

func _on_options_pressed():
    print("Opening options...")

func _on_quit_pressed():
    get_tree().quit()
"""
        script_path = demo_project_copy / "ui" / "main_menu.gd"
        script_path.parent.mkdir(parents=True, exist_ok=True)
        script_path.write_text(menu_script, encoding="utf-8")

        script_attach(
            project_path=str(demo_project_copy),
            scene_path="ui/main_menu.tscn",
            node_path="root",
            script_path="ui/main_menu.gd",
        )

        # Step 4: Connect button signals
        button_signals = [
            ("root/MenuContainer/StartButton", "_on_start_pressed"),
            ("root/MenuContainer/OptionsButton", "_on_options_pressed"),
            ("root/MenuContainer/QuitButton", "_on_quit_pressed"),
        ]

        for source_path, method_name in button_signals:
            result = signal_connect(
                project_path=str(demo_project_copy),
                scene_path="ui/main_menu.tscn",
                source_node_path=source_path,
                signal_name="pressed",
                target_node_path="root",
                method_name=method_name,
            )
            assert "error" not in result.lower()

        # Verify scene has connections
        scene_file = demo_project_copy / "ui" / "main_menu.tscn"
        content = scene_file.read_text(encoding="utf-8")
        assert "connection" in content.lower() or "signal" in content.lower()
