"""Tests for godotiq.cli argument parsing and dispatch."""

import subprocess
import sys
from pathlib import Path

import pytest

from godotiq.cli import install_addon


class TestCliParsing:
    """Test argparse routing in cli.py."""

    def test_no_args_defaults_to_serve(self, monkeypatch):
        """When invoked with no arguments, cli_main should dispatch to _serve."""
        served = []
        monkeypatch.setattr("godotiq.cli._serve", lambda: served.append(True))
        monkeypatch.setattr("sys.argv", ["godotiq"])
        from godotiq.cli import cli_main
        cli_main()
        assert served == [True]

    def test_version_flag(self, monkeypatch, capsys):
        """godotiq --version should print the version and exit."""
        monkeypatch.setattr("sys.argv", ["godotiq", "--version"])
        from godotiq.cli import cli_main
        with pytest.raises(SystemExit) as exc_info:
            cli_main()
        assert exc_info.value.code == 0
        captured = capsys.readouterr()
        from godotiq import __version__
        assert __version__ in captured.out

    def test_help_flag(self, monkeypatch, capsys):
        """godotiq --help should print help text and exit."""
        monkeypatch.setattr("sys.argv", ["godotiq", "--help"])
        from godotiq.cli import cli_main
        with pytest.raises(SystemExit) as exc_info:
            cli_main()
        assert exc_info.value.code == 0
        captured = capsys.readouterr()
        assert "install-addon" in captured.out

    def test_install_addon_requires_path(self, monkeypatch):
        """install-addon with no path argument should fail."""
        monkeypatch.setattr("sys.argv", ["godotiq", "install-addon"])
        from godotiq.cli import cli_main
        with pytest.raises(SystemExit) as exc_info:
            cli_main()
        assert exc_info.value.code != 0

    def test_install_addon_accepts_path(self, monkeypatch, tmp_path):
        """install-addon with a path argument should be accepted."""
        called_with = {}
        def mock_install(target_dir, dry_run=False):
            called_with["target_dir"] = target_dir
            called_with["dry_run"] = dry_run
        monkeypatch.setattr("godotiq.cli.install_addon", mock_install)
        monkeypatch.setattr("sys.argv", ["godotiq", "install-addon", str(tmp_path)])
        from godotiq.cli import cli_main
        cli_main()
        assert called_with["target_dir"] == str(tmp_path)
        assert called_with["dry_run"] is False

    def test_install_addon_dry_run_flag(self, monkeypatch, tmp_path):
        """install-addon --dry-run should set dry_run=True."""
        called_with = {}
        def mock_install(target_dir, dry_run=False):
            called_with["dry_run"] = dry_run
        monkeypatch.setattr("godotiq.cli.install_addon", mock_install)
        monkeypatch.setattr("sys.argv", ["godotiq", "install-addon", "--dry-run", str(tmp_path)])
        from godotiq.cli import cli_main
        cli_main()
        assert called_with["dry_run"] is True

    def test_unknown_subcommand_errors(self, monkeypatch):
        """Unknown subcommand should produce an error exit."""
        monkeypatch.setattr("sys.argv", ["godotiq", "nonexistent"])
        from godotiq.cli import cli_main
        with pytest.raises(SystemExit) as exc_info:
            cli_main()
        assert exc_info.value.code != 0


class TestLazyImports:
    """Verify cli.py does not eagerly import server.py."""

    def test_cli_import_does_not_import_server(self):
        """Importing godotiq.cli should not trigger import of godotiq.server."""
        result = subprocess.run(
            [sys.executable, "-c",
             "import godotiq.cli; import sys; print('godotiq.server' not in sys.modules)"],
            capture_output=True, text=True, timeout=10,
        )
        assert result.returncode == 0
        assert "True" in result.stdout

    def test_install_addon_path_does_not_import_server(self, tmp_path):
        """The install-addon code path should not import godotiq.server."""
        script = tmp_path / "check_lazy.py"
        script.write_text(
            "import sys\n"
            "sys.argv = ['godotiq', 'install-addon', '/tmp/fake']\n"
            "from godotiq.cli import cli_main\n"
            "try:\n"
            "    cli_main()\n"
            "except SystemExit:\n"
            "    pass\n"
            "print('godotiq.server' not in sys.modules)\n"
        )
        result = subprocess.run(
            [sys.executable, str(script)],
            capture_output=True, text=True, timeout=10,
        )
        assert "True" in result.stdout


def _make_godot_project(tmp_path):
    """Create a minimal fake Godot project directory with a project.godot file."""
    (tmp_path / "project.godot").write_text("[gd_resource]\n")
    return tmp_path


class TestInstallAddonCopying:
    """Test install_addon file copying behavior."""

    def test_install_addon_copies_gd_files(self, tmp_path):
        """install_addon copies all .gd files to target/addons/godotiq/."""
        project = _make_godot_project(tmp_path)
        install_addon(str(project))
        gd_files = list((project / "addons" / "godotiq").glob("*.gd"))
        assert len(gd_files) >= 5, f"Expected >= 5 .gd files, got {gd_files}"

    def test_install_addon_copies_plugin_cfg(self, tmp_path):
        """install_addon copies plugin.cfg to target/addons/godotiq/."""
        project = _make_godot_project(tmp_path)
        install_addon(str(project))
        assert (project / "addons" / "godotiq" / "plugin.cfg").exists()

    def test_install_addon_copies_godotiq_rules(self, tmp_path):
        """install_addon copies GODOTIQ_RULES.md to the target project root."""
        project = _make_godot_project(tmp_path)
        install_addon(str(project))
        rules = project / "GODOTIQ_RULES.md"
        assert rules.exists()
        content = rules.read_text()
        assert len(content) > 100, "GODOTIQ_RULES.md should have substantial content"

    def test_install_addon_creates_addons_dir(self, tmp_path):
        """install_addon creates addons/godotiq/ directory if it does not exist."""
        project = _make_godot_project(tmp_path)
        assert not (project / "addons").exists()
        install_addon(str(project))
        assert (project / "addons" / "godotiq").is_dir()


class TestInstallAddonOverwrite:
    """Test install_addon overwrite behavior."""

    def test_install_addon_overwrites_existing_files(self, tmp_path, capsys):
        """install_addon overwrites existing files and reports 'updated'."""
        project = _make_godot_project(tmp_path)
        addon_dir = project / "addons" / "godotiq"
        addon_dir.mkdir(parents=True)
        (addon_dir / "plugin.cfg").write_text("old content")
        install_addon(str(project))
        assert (addon_dir / "plugin.cfg").read_text() != "old content"
        captured = capsys.readouterr()
        assert "updated" in captured.out

    def test_install_addon_reports_added_for_new_files(self, tmp_path, capsys):
        """install_addon reports 'added' for files that did not previously exist."""
        project = _make_godot_project(tmp_path)
        install_addon(str(project))
        captured = capsys.readouterr()
        assert "added" in captured.out


class TestInstallAddonValidation:
    """Test install_addon validation errors."""

    def test_install_addon_fails_nonexistent_dir(self):
        """install_addon raises SystemExit for non-existent target."""
        with pytest.raises(SystemExit):
            install_addon("/nonexistent/path/abc123")

    def test_install_addon_fails_no_project_godot(self, tmp_path):
        """install_addon raises SystemExit when target has no project.godot."""
        with pytest.raises(SystemExit):
            install_addon(str(tmp_path))

    def test_install_addon_resolves_relative_paths(self, tmp_path, monkeypatch):
        """install_addon resolves relative paths correctly."""
        (tmp_path / "myproject").mkdir()
        project = _make_godot_project(tmp_path / "myproject")
        monkeypatch.chdir(tmp_path)
        install_addon("myproject")
        assert (project / "addons" / "godotiq").is_dir()


class TestInstallAddonDryRun:
    """Test install_addon --dry-run behavior."""

    def test_install_addon_dry_run_creates_no_files(self, tmp_path, capsys):
        """--dry-run lists files but does not copy anything."""
        project = _make_godot_project(tmp_path)
        install_addon(str(project), dry_run=True)
        assert not (project / "addons" / "godotiq").exists()

    def test_install_addon_dry_run_still_validates(self, tmp_path):
        """--dry-run still validates the target directory."""
        with pytest.raises(SystemExit):
            install_addon("/nonexistent/path", dry_run=True)

    def test_install_addon_dry_run_lists_files(self, tmp_path, capsys):
        """--dry-run prints the list of files that would be copied."""
        project = _make_godot_project(tmp_path)
        install_addon(str(project), dry_run=True)
        captured = capsys.readouterr()
        assert "would copy" in captured.out
        assert "plugin.cfg" in captured.out


class TestInstallAddonLazyImport:
    """Verify install-addon does not import server."""

    def test_install_addon_does_not_import_server(self, tmp_path):
        """The install_addon code path does NOT import godotiq.server."""
        project = _make_godot_project(tmp_path)
        script = tmp_path / "check_server.py"
        script.write_text(
            f"import sys\n"
            f"from godotiq.cli import install_addon\n"
            f"install_addon('{project}')\n"
            f"print('godotiq.server' not in sys.modules)\n"
        )
        result = subprocess.run(
            [sys.executable, str(script)],
            capture_output=True, text=True, timeout=10,
        )
        assert "True" in result.stdout


class TestMainModule:
    """Test python -m godotiq routing."""

    def test_python_m_version(self):
        """python -m godotiq --version should print the version."""
        result = subprocess.run(
            [sys.executable, "-m", "godotiq", "--version"],
            capture_output=True, text=True, timeout=10,
        )
        assert result.returncode == 0
        from godotiq import __version__
        assert __version__ in result.stdout

    def test_python_m_help(self):
        """python -m godotiq --help should succeed."""
        result = subprocess.run(
            [sys.executable, "-m", "godotiq", "--help"],
            capture_output=True, text=True, timeout=10,
        )
        assert result.returncode == 0
        assert "install-addon" in result.stdout
