"""Tests for godotiq_impact_check tool."""

from __future__ import annotations

from godotiq.parsers.gd_parser import GdScript, GdAutoloadRef
from godotiq.session import GodotIQSession
from godotiq.tools.code import _build_impact_check


class TestImpactCheckModifyFunction:
    def test_impact_modify_function(self, session: GodotIQSession) -> None:
        """Modifying an autoload function finds dependents as callers."""
        result = _build_impact_check(
            session,
            "res://scripts/autoloads/economy_manager.gd",
            "modify_function",
            "add_cash",
        )
        assert result["file"] == "res://scripts/autoloads/economy_manager.gd"
        assert result["action"] == "modify_function"
        assert result["target"] == "add_cash"
        # progression_manager references EconomyManager autoload
        caller_files = [c["file"] for c in result["callers"]]
        assert "res://scripts/autoloads/progression_manager.gd" in caller_files
        assert result["risk"] in ("medium", "high", "critical")
        assert result["total_files_affected"] >= 1


class TestImpactCheckRenameSignal:
    def test_impact_rename_signal(self, session: GodotIQSession) -> None:
        """Renaming a signal finds emitters in signal_impact."""
        result = _build_impact_check(
            session,
            "res://scripts/autoloads/economy_manager.gd",
            "rename_signal",
            "cash_changed",
        )
        assert result["action"] == "rename_signal"
        assert "signal_impact" in result
        # economy_manager emits cash_changed, so it should appear
        assert len(result["signal_impact"]) >= 1


class TestImpactCheckAddParameter:
    def test_impact_add_parameter(self, session: GodotIQSession) -> None:
        """Adding a parameter suggests default value as safe alternative."""
        result = _build_impact_check(
            session,
            "res://scripts/autoloads/economy_manager.gd",
            "add_parameter",
            "add_cash",
            "tax_rate",
        )
        assert result["action"] == "add_parameter"
        assert "safe_alternative" in result
        assert "default" in result["safe_alternative"].lower()


class TestImpactCheckRemoveFunction:
    def test_impact_remove_function(self, session: GodotIQSession) -> None:
        """Removing a function lists callers as breaking."""
        result = _build_impact_check(
            session,
            "res://scripts/autoloads/economy_manager.gd",
            "remove_function",
            "get_profit",
        )
        assert result["action"] == "remove_function"
        # progression_manager calls EconomyManager
        caller_files = [c["file"] for c in result["callers"]]
        assert "res://scripts/autoloads/progression_manager.gd" in caller_files
        assert "safe_alternative" in result


class TestImpactCheckLowRisk:
    def test_impact_low_risk(self, session: GodotIQSession) -> None:
        """Isolated file with no external callers gets low risk."""
        result = _build_impact_check(
            session,
            "res://scripts/entities/worker.gd",
            "modify_function",
            "some_func",
        )
        assert result["risk"] == "low"
        assert result["total_files_affected"] == 0


class TestImpactCheckCriticalRisk:
    def test_impact_critical_risk(self, session: GodotIQSession) -> None:
        """Autoload with 5+ dependent scripts gets critical risk."""
        fake_paths = []
        for i in range(6):
            fake_path = f"res://scripts/fake_{i}.gd"
            fake_gd = GdScript()
            fake_gd.autoload_refs = [
                GdAutoloadRef(
                    autoload_name="EconomyManager",
                    access="direct",
                    pattern="direct",
                    line=1,
                )
            ]
            session._gd_scripts[fake_path] = fake_gd
            fake_paths.append(fake_path)
        try:
            result = _build_impact_check(
                session,
                "res://scripts/autoloads/economy_manager.gd",
                "modify_function",
                "add_cash",
            )
            assert result["risk"] == "critical"
            assert result["total_files_affected"] >= 5
        finally:
            for fake_path in fake_paths:
                session._gd_scripts.pop(fake_path, None)


class TestImpactCheckMissingFile:
    def test_impact_missing_file(self, session: GodotIQSession) -> None:
        """Non-existent file returns error dict."""
        result = _build_impact_check(
            session,
            "res://nonexistent.gd",
            "modify_function",
            "some_func",
        )
        assert "error" in result


class TestImpactCheckFilesToUpdate:
    def test_impact_files_to_update(self, session: GodotIQSession) -> None:
        """files_to_update is a deduplicated list."""
        result = _build_impact_check(
            session,
            "res://scripts/autoloads/economy_manager.gd",
            "modify_function",
            "add_cash",
        )
        assert "files_to_update" in result
        files = result["files_to_update"]
        assert isinstance(files, list)
        assert len(files) == len(set(files))
