"""Tests for distro module."""

import pytest

from gaol.distro import (
    DistroFamily,
    DistroInfo,
    PackageManager,
    ServiceManager,
    get_cloud_image_url,
    get_debootstrap_cmd,
    get_distro_family,
    get_distro_info,
    get_docker_image,
    get_mirror,
    get_package_manager_commands,
    get_service_commands,
    list_supported_distros,
    translate_package,
    translate_packages,
    translate_service,
)


class TestDistroRegistry:
    """Tests for distro registry and info."""

    def test_list_supported_distros(self) -> None:
        """Test listing all supported distros."""
        distros = list_supported_distros()
        assert len(distros) >= 9
        assert "trixie" in distros
        assert "bookworm" in distros
        assert "noble" in distros
        assert "fedora" in distros
        assert "alpine" in distros
        assert "arch" in distros

    def test_get_distro_info_debian(self) -> None:
        """Test getting info for Debian distro."""
        info = get_distro_info("trixie")
        assert isinstance(info, DistroInfo)
        assert info.name == "trixie"
        assert info.family == DistroFamily.DEBIAN
        assert info.package_manager == PackageManager.APT
        assert info.service_manager == ServiceManager.SYSTEMD
        assert info.docker_image == "debian:trixie"
        assert info.cloud_image_url is not None
        assert info.debootstrap_cmd is not None

    def test_get_distro_info_ubuntu(self) -> None:
        """Test getting info for Ubuntu distro."""
        info = get_distro_info("noble")
        assert info.name == "noble"
        assert info.family == DistroFamily.DEBIAN
        assert info.package_manager == PackageManager.APT
        assert "ubuntu" in info.docker_image.lower()

    def test_get_distro_info_fedora(self) -> None:
        """Test getting info for Fedora distro."""
        info = get_distro_info("fedora")
        assert info.name == "fedora"
        assert info.family == DistroFamily.REDHAT
        assert info.package_manager == PackageManager.DNF
        assert info.service_manager == ServiceManager.SYSTEMD

    def test_get_distro_info_alpine(self) -> None:
        """Test getting info for Alpine distro."""
        info = get_distro_info("alpine")
        assert info.name == "alpine"
        assert info.family == DistroFamily.ALPINE
        assert info.package_manager == PackageManager.APK
        assert info.service_manager == ServiceManager.OPENRC

    def test_get_distro_info_arch(self) -> None:
        """Test getting info for Arch distro."""
        info = get_distro_info("arch")
        assert info.name == "arch"
        assert info.family == DistroFamily.ARCH
        assert info.package_manager == PackageManager.PACMAN
        assert info.service_manager == ServiceManager.SYSTEMD

    def test_get_distro_info_unknown(self) -> None:
        """Test getting info for unknown distro raises KeyError."""
        with pytest.raises(KeyError, match="Unknown distribution"):
            get_distro_info("unknown-distro")

    def test_get_distro_family(self) -> None:
        """Test getting distro family."""
        assert get_distro_family("trixie") == DistroFamily.DEBIAN
        assert get_distro_family("fedora") == DistroFamily.REDHAT
        assert get_distro_family("alpine") == DistroFamily.ALPINE
        assert get_distro_family("arch") == DistroFamily.ARCH


class TestPackageTranslation:
    """Tests for package name translation."""

    def test_translate_package_simple(self) -> None:
        """Test simple package translation."""
        # curl is the same across distros
        assert translate_package("curl", "trixie") == "curl"
        assert translate_package("curl", "fedora") == "curl"
        assert translate_package("curl", "alpine") == "curl"

    def test_translate_package_vim(self) -> None:
        """Test vim package translation."""
        assert translate_package("vim", "trixie") == "vim"
        assert translate_package("vim", "fedora") == "vim-enhanced"
        assert translate_package("vim", "alpine") == "vim"
        assert translate_package("vim", "arch") == "vim"

    def test_translate_package_iputils(self) -> None:
        """Test iputils-ping translation."""
        assert translate_package("iputils-ping", "trixie") == "iputils-ping"
        assert translate_package("iputils-ping", "fedora") == "iputils"
        assert translate_package("iputils-ping", "alpine") == "iputils"
        assert translate_package("iputils-ping", "arch") == "iputils"

    def test_translate_package_python(self) -> None:
        """Test Python package translation."""
        assert translate_package("python3-pip", "trixie") == "python3-pip"
        assert translate_package("python3-pip", "alpine") == "py3-pip"
        assert translate_package("python3-pip", "arch") == "python-pip"

    def test_translate_package_unknown(self) -> None:
        """Test unknown package returns as-is."""
        # Unknown packages should be returned unchanged
        assert translate_package("unknown-package", "trixie") == "unknown-package"

    def test_translate_packages_list(self) -> None:
        """Test translating a list of packages."""
        packages = ["vim", "curl", "iputils-ping"]
        translated = translate_packages(packages, "fedora")

        assert "vim-enhanced" in translated
        assert "curl" in translated
        assert "iputils" in translated
        assert len(translated) == 3

    def test_translate_packages_filters_none(self) -> None:
        """Test that unavailable packages are filtered out."""
        # Test with a package that might not exist on some distros
        packages = ["curl", "wget"]
        translated = translate_packages(packages, "trixie")
        assert len(translated) == 2


class TestServiceTranslation:
    """Tests for service name translation."""

    def test_translate_service_ssh(self) -> None:
        """Test SSH service translation."""
        assert translate_service("ssh", "trixie") == "ssh"
        assert translate_service("ssh", "fedora") == "sshd"
        assert translate_service("ssh", "alpine") == "sshd"
        assert translate_service("ssh", "arch") == "sshd"

    def test_translate_service_unknown(self) -> None:
        """Test unknown service returns as-is."""
        assert translate_service("custom-service", "trixie") == "custom-service"


class TestPackageManagerCommands:
    """Tests for package manager commands."""

    def test_apt_commands(self) -> None:
        """Test APT package manager commands."""
        commands = get_package_manager_commands("trixie")
        assert "apt-get update" in commands["update"]
        assert "apt-get install -y" in commands["install"]

    def test_dnf_commands(self) -> None:
        """Test DNF package manager commands."""
        commands = get_package_manager_commands("fedora")
        assert "dnf" in commands["update"]
        assert "dnf install -y" in commands["install"]

    def test_apk_commands(self) -> None:
        """Test APK package manager commands."""
        commands = get_package_manager_commands("alpine")
        assert "apk update" in commands["update"]
        assert "apk add" in commands["install"]

    def test_pacman_commands(self) -> None:
        """Test Pacman package manager commands."""
        commands = get_package_manager_commands("arch")
        assert "pacman -Sy" in commands["update"]
        assert "pacman -S --noconfirm" in commands["install"]


class TestServiceCommands:
    """Tests for service management commands."""

    def test_systemd_commands(self) -> None:
        """Test systemd service commands."""
        assert get_service_commands("trixie", "ssh", "enable") == "systemctl enable ssh"
        assert get_service_commands("trixie", "ssh", "start") == "systemctl start ssh"

    def test_systemd_with_translation(self) -> None:
        """Test systemd commands with service name translation."""
        assert get_service_commands("fedora", "ssh", "enable") == "systemctl enable sshd"
        assert get_service_commands("fedora", "ssh", "start") == "systemctl start sshd"

    def test_openrc_commands(self) -> None:
        """Test OpenRC service commands (Alpine)."""
        assert get_service_commands("alpine", "ssh", "enable") == "rc-update add sshd"
        assert get_service_commands("alpine", "ssh", "start") == "rc-service sshd start"
        assert get_service_commands("alpine", "ssh", "stop") == "rc-service sshd stop"


class TestImageAndBootstrap:
    """Tests for Docker images and bootstrap commands."""

    def test_get_docker_image(self) -> None:
        """Test getting Docker images."""
        assert get_docker_image("trixie") == "debian:trixie"
        assert get_docker_image("noble") == "ubuntu:noble"
        assert get_docker_image("fedora") == "fedora:41"
        assert get_docker_image("alpine") == "alpine:3.20"
        assert "archlinux" in get_docker_image("arch")

    def test_get_docker_image_unknown(self) -> None:
        """Test getting Docker image for unknown distro."""
        with pytest.raises(KeyError):
            get_docker_image("unknown")

    def test_get_cloud_image_url(self) -> None:
        """Test getting cloud image URLs."""
        url = get_cloud_image_url("trixie")
        assert "cloud.debian.org" in url

        url = get_cloud_image_url("noble")
        assert "cloud-images.ubuntu.com" in url

        url = get_cloud_image_url("fedora")
        assert "fedoraproject.org" in url

    def test_get_cloud_image_url_no_image(self) -> None:
        """Test getting cloud image for distro without one."""
        # Arch doesn't have official cloud images
        with pytest.raises(KeyError):
            get_cloud_image_url("arch")

    def test_get_debootstrap_cmd(self) -> None:
        """Test getting debootstrap commands."""
        cmd = get_debootstrap_cmd("trixie")
        assert "debootstrap" in cmd
        assert "trixie" in cmd

    def test_get_debootstrap_cmd_non_debian(self) -> None:
        """Test debootstrap not available for non-Debian distros."""
        with pytest.raises(KeyError):
            get_debootstrap_cmd("fedora")

        with pytest.raises(KeyError):
            get_debootstrap_cmd("alpine")

    def test_get_mirror(self) -> None:
        """Test getting package mirrors."""
        assert "debian.org" in get_mirror("trixie")
        assert "ubuntu.com" in get_mirror("noble")
        assert get_mirror("fedora") is None  # Fedora doesn't use mirrors this way
