"""Tests for CLI commands."""

from typer.testing import CliRunner

from gaol import __version__
from gaol.cli import app

runner = CliRunner()


class TestCLI:
    """Tests for CLI commands."""

    def test_version(self) -> None:
        """Test version command."""
        result = runner.invoke(app, ["--version"])
        assert result.exit_code == 0
        assert __version__ in result.stdout

    def test_help(self) -> None:
        """Test help command."""
        result = runner.invoke(app, ["--help"])
        assert result.exit_code == 0
        assert "gaol" in result.stdout.lower()
        assert "create" in result.stdout
        assert "start" in result.stdout
        assert "stop" in result.stdout

    def test_create_help(self) -> None:
        """Test create command help."""
        result = runner.invoke(app, ["create", "--help"])
        assert result.exit_code == 0
        assert "--runtime" in result.stdout
        assert "--distro" in result.stdout
        assert "--profile" in result.stdout

    def test_list_help(self) -> None:
        """Test list command help."""
        result = runner.invoke(app, ["list", "--help"])
        assert result.exit_code == 0
        assert "--all" in result.stdout

    def test_exec_help(self) -> None:
        """Test exec command help."""
        result = runner.invoke(app, ["exec", "--help"])
        assert result.exit_code == 0
        assert "--user" in result.stdout
        assert "--workdir" in result.stdout

    def test_runtimes_command(self) -> None:
        """Test runtimes command."""
        result = runner.invoke(app, ["runtimes"])
        assert result.exit_code == 0
        assert "docker" in result.stdout.lower()
        assert "nspawn" in result.stdout.lower()

    def test_profiles_list(self) -> None:
        """Test profiles list command."""
        result = runner.invoke(app, ["profiles", "list"])
        assert result.exit_code == 0
        assert "base" in result.stdout.lower()
        assert "tailscale" in result.stdout.lower()

    def test_profiles_show(self) -> None:
        """Test profiles show command."""
        result = runner.invoke(app, ["profiles", "show", "base"])
        assert result.exit_code == 0
        assert "base" in result.stdout.lower()
        assert "packages" in result.stdout.lower()

    def test_profiles_show_nonexistent(self) -> None:
        """Test profiles show with nonexistent profile."""
        result = runner.invoke(app, ["profiles", "show", "nonexistent-profile"])
        assert result.exit_code == 1
        # Error message goes to stderr, which is mixed into output
        assert "not found" in result.output.lower()

    def test_profiles_resolve(self) -> None:
        """Test profiles resolve command."""
        result = runner.invoke(app, ["profiles", "resolve", "tailscale"])
        assert result.exit_code == 0
        assert "base" in result.stdout.lower()
        assert "tailscale" in result.stdout.lower()

    def test_profiles_resolve_chain(self) -> None:
        """Test profiles resolve with dependency chain."""
        result = runner.invoke(app, ["profiles", "resolve", "sunshine"])
        assert result.exit_code == 0
        # sunshine depends on gui, which depends on base
        lines = result.stdout.lower()
        assert "base" in lines
        assert "gui" in lines
        assert "sunshine" in lines

    def test_profiles_help(self) -> None:
        """Test profiles subcommand help."""
        result = runner.invoke(app, ["profiles", "--help"])
        assert result.exit_code == 0
        assert "list" in result.stdout
        assert "show" in result.stdout
        assert "resolve" in result.stdout

    def test_list_stored_help(self) -> None:
        """Test list command with --stored option in help."""
        result = runner.invoke(app, ["list", "--help"])
        assert result.exit_code == 0
        assert "--stored" in result.stdout
        assert "--all-runtimes" in result.stdout

    def test_inspect_help(self) -> None:
        """Test inspect command help."""
        result = runner.invoke(app, ["inspect", "--help"])
        assert result.exit_code == 0
        assert "--json" in result.stdout

    def test_inspect_nonexistent(self) -> None:
        """Test inspect with nonexistent container."""
        result = runner.invoke(app, ["inspect", "nonexistent-container-xyz"])
        assert result.exit_code == 1
        assert "not found" in result.output.lower()

    def test_destroy_keep_config_help(self) -> None:
        """Test destroy command has --keep-config option."""
        result = runner.invoke(app, ["destroy", "--help"])
        assert result.exit_code == 0
        assert "--keep-config" in result.stdout

    def test_cp_help(self) -> None:
        """Test cp command help."""
        result = runner.invoke(app, ["cp", "--help"])
        assert result.exit_code == 0
        assert "container:path" in result.stdout.lower()

    def test_cp_requires_container_path(self) -> None:
        """Test cp command requires at least one container path."""
        result = runner.invoke(app, ["cp", "/local/file", "/other/local"])
        assert result.exit_code == 1
        assert "container path" in result.output.lower()

    def test_cp_no_container_to_container(self) -> None:
        """Test cp command doesn't allow container-to-container copy."""
        result = runner.invoke(app, ["cp", "container1:/path", "container2:/path"])
        assert result.exit_code == 1
        assert "cannot copy between two containers" in result.output.lower()

    def test_profiles_validate_help(self) -> None:
        """Test profiles validate command help."""
        result = runner.invoke(app, ["profiles", "validate", "--help"])
        assert result.exit_code == 0
        assert "yaml" in result.stdout.lower()

    def test_profiles_validate_nonexistent(self) -> None:
        """Test profiles validate with nonexistent file."""
        result = runner.invoke(app, ["profiles", "validate", "/nonexistent/profile.yaml"])
        assert result.exit_code == 1
        assert "not found" in result.output.lower()


class TestCpPathParsing:
    """Tests for copy path parsing."""

    def test_parse_local_path(self) -> None:
        """Test parsing local paths."""
        from gaol.cli import _parse_copy_path

        container, path = _parse_copy_path("/local/path")
        assert container is None
        assert path == "/local/path"

    def test_parse_container_path(self) -> None:
        """Test parsing container paths."""
        from gaol.cli import _parse_copy_path

        container, path = _parse_copy_path("mycontainer:/etc/passwd")
        assert container == "mycontainer"
        assert path == "/etc/passwd"

    def test_parse_relative_path(self) -> None:
        """Test parsing relative paths."""
        from gaol.cli import _parse_copy_path

        container, path = _parse_copy_path("./local/file.txt")
        assert container is None
        assert path == "./local/file.txt"

    def test_parse_windows_path(self) -> None:
        """Test parsing Windows-style paths."""
        from gaol.cli import _parse_copy_path

        # Single letter followed by colon is treated as Windows drive
        container, path = _parse_copy_path("C:\\Users\\test")
        assert container is None
        assert path == "C:\\Users\\test"


class TestSnapshotCLI:
    """Tests for snapshot CLI commands."""

    def test_snapshot_help(self) -> None:
        """Test snapshot subcommand help."""
        result = runner.invoke(app, ["snapshot", "--help"])
        assert result.exit_code == 0
        assert "create" in result.stdout
        assert "list" in result.stdout
        assert "restore" in result.stdout
        assert "delete" in result.stdout

    def test_snapshot_create_help(self) -> None:
        """Test snapshot create command help."""
        result = runner.invoke(app, ["snapshot", "create", "--help"])
        assert result.exit_code == 0
        assert "container" in result.stdout.lower()
        assert "name" in result.stdout.lower()
        assert "--description" in result.stdout

    def test_snapshot_list_help(self) -> None:
        """Test snapshot list command help."""
        result = runner.invoke(app, ["snapshot", "list", "--help"])
        assert result.exit_code == 0
        assert "container" in result.stdout.lower()

    def test_snapshot_restore_help(self) -> None:
        """Test snapshot restore command help."""
        result = runner.invoke(app, ["snapshot", "restore", "--help"])
        assert result.exit_code == 0
        assert "container" in result.stdout.lower()
        assert "name" in result.stdout.lower()

    def test_snapshot_delete_help(self) -> None:
        """Test snapshot delete command help."""
        result = runner.invoke(app, ["snapshot", "delete", "--help"])
        assert result.exit_code == 0
        assert "container" in result.stdout.lower()
        assert "name" in result.stdout.lower()
        assert "--force" in result.stdout

    def test_snapshot_create_nonexistent_container(self) -> None:
        """Test snapshot create with nonexistent container."""
        result = runner.invoke(app, ["snapshot", "create", "nonexistent-xyz", "snap1"])
        assert result.exit_code == 1
        # Error message should indicate failure

    def test_snapshot_list_nonexistent_container(self) -> None:
        """Test snapshot list with nonexistent container."""
        result = runner.invoke(app, ["snapshot", "list", "nonexistent-xyz"])
        assert result.exit_code == 1


class TestExportImportCLI:
    """Tests for export/import CLI commands."""

    def test_export_help(self) -> None:
        """Test export command help."""
        result = runner.invoke(app, ["export", "--help"])
        assert result.exit_code == 0
        assert "--output" in result.stdout
        assert "--json" in result.stdout

    def test_export_nonexistent_container(self) -> None:
        """Test export with nonexistent container."""
        result = runner.invoke(app, ["export", "nonexistent-xyz"])
        assert result.exit_code == 1
        assert "not found" in result.output.lower()

    def test_import_config_help(self) -> None:
        """Test import-config command help."""
        result = runner.invoke(app, ["import-config", "--help"])
        assert result.exit_code == 0
        assert "--name" in result.stdout
        assert "--create" in result.stdout
        assert "--start" in result.stdout

    def test_import_config_nonexistent_file(self) -> None:
        """Test import-config with nonexistent file."""
        result = runner.invoke(app, ["import-config", "/nonexistent/file.yaml"])
        assert result.exit_code == 1
        assert "not found" in result.output.lower()


class TestSshConfigCLI:
    """Tests for ssh-config CLI command."""

    def test_ssh_config_help(self) -> None:
        """Test ssh-config command help."""
        result = runner.invoke(app, ["ssh-config", "--help"])
        assert result.exit_code == 0
        assert "--user" in result.stdout
        assert "--port" in result.stdout
        assert "--identity" in result.stdout
        assert "--append" in result.stdout

    def test_ssh_config_generate_entry(self) -> None:
        """Test SSH config entry generation helper."""
        from gaol.cli import _generate_ssh_config_entry

        entry = _generate_ssh_config_entry(
            name="test-container",
            ip_address="172.17.0.2",
            user="root",
            port=22,
            identity=None,
        )

        assert "Host test-container" in entry
        assert "HostName 172.17.0.2" in entry
        assert "User root" in entry
        assert "StrictHostKeyChecking no" in entry

    def test_ssh_config_generate_entry_with_options(self) -> None:
        """Test SSH config entry generation with custom options."""
        from gaol.cli import _generate_ssh_config_entry

        entry = _generate_ssh_config_entry(
            name="mycontainer",
            ip_address="10.0.0.5",
            user="admin",
            port=2222,
            identity="/path/to/key",
        )

        assert "Host mycontainer" in entry
        assert "HostName 10.0.0.5" in entry
        assert "User admin" in entry
        assert "Port 2222" in entry
        assert "IdentityFile /path/to/key" in entry


class TestStatsCLI:
    """Tests for stats CLI command."""

    def test_stats_help(self) -> None:
        """Test stats command help."""
        result = runner.invoke(app, ["stats", "--help"])
        assert result.exit_code == 0
        assert "--json" in result.stdout
        assert "--watch" in result.stdout
        assert "--interval" in result.stdout

    def test_stats_nonexistent_container(self) -> None:
        """Test stats with nonexistent container."""
        result = runner.invoke(app, ["stats", "nonexistent-xyz"])
        assert result.exit_code == 1
