"""Tests for container runtimes."""

import pytest

from gaol.runtimes import get_runtime, list_available_runtimes
from gaol.runtimes.base import ContainerRuntime
from gaol.runtimes.docker import DockerRuntime
from gaol.runtimes.libvirt import LibvirtRuntime
from gaol.runtimes.nspawn import NspawnRuntime


class TestRuntimeRegistry:
    """Tests for runtime registry functions."""

    def test_get_runtime_docker(self) -> None:
        """Test getting docker runtime."""
        rt = get_runtime("docker")
        assert isinstance(rt, DockerRuntime)
        assert rt.name == "docker"

    def test_get_runtime_nspawn(self) -> None:
        """Test getting nspawn runtime."""
        rt = get_runtime("nspawn")
        assert isinstance(rt, NspawnRuntime)
        assert rt.name == "nspawn"

    def test_get_runtime_unknown(self) -> None:
        """Test getting unknown runtime raises error."""
        with pytest.raises(ValueError, match="Unknown runtime"):
            get_runtime("unknown-runtime")

    def test_list_available_runtimes(self) -> None:
        """Test listing available runtimes."""
        runtimes = list_available_runtimes()
        assert len(runtimes) >= 2

        names = [name for name, _ in runtimes]
        assert "docker" in names
        assert "nspawn" in names


class TestDockerRuntime:
    """Tests for Docker runtime."""

    def test_runtime_name(self) -> None:
        """Test runtime name property."""
        rt = DockerRuntime()
        assert rt.name == "docker"

    def test_is_container_runtime(self) -> None:
        """Test that DockerRuntime is a ContainerRuntime."""
        rt = DockerRuntime()
        assert isinstance(rt, ContainerRuntime)


class TestNspawnRuntime:
    """Tests for systemd-nspawn runtime."""

    def test_runtime_name(self) -> None:
        """Test runtime name property."""
        rt = NspawnRuntime()
        assert rt.name == "nspawn"

    def test_is_container_runtime(self) -> None:
        """Test that NspawnRuntime is a ContainerRuntime."""
        rt = NspawnRuntime()
        assert isinstance(rt, ContainerRuntime)

    def test_nspawn_config_generation(self) -> None:
        """Test nspawn configuration file generation."""
        from gaol.models.container import (
            ContainerConfig,
            NetworkConfig,
            NetworkMode,
        )

        rt = NspawnRuntime()

        config = ContainerConfig(
            name="test-container",
            runtime="nspawn",
            distro="trixie",
            network=NetworkConfig(
                mode=NetworkMode.SHARED,
                ports={8080: 80},
            ),
            environment={"TEST_VAR": "test_value"},
            volumes={"/host/path": "/container/path"},
        )

        nspawn_config = rt._generate_nspawn_config(config)

        assert "[Exec]" in nspawn_config
        assert "Boot=yes" in nspawn_config
        assert "[Network]" in nspawn_config
        assert "Port=tcp:8080:80" in nspawn_config
        assert "Environment=TEST_VAR=test_value" in nspawn_config
        assert "[Files]" in nspawn_config
        assert "Bind=/host/path:/container/path" in nspawn_config

    def test_nspawn_bridged_network_config(self) -> None:
        """Test nspawn config with bridged network."""
        from gaol.models.container import ContainerConfig, NetworkConfig, NetworkMode

        rt = NspawnRuntime()

        config = ContainerConfig(
            name="bridged-container",
            runtime="nspawn",
            network=NetworkConfig(mode=NetworkMode.BRIDGED),
        )

        nspawn_config = rt._generate_nspawn_config(config)
        assert "Bridge=br0" in nspawn_config

    def test_nspawn_host_network_config(self) -> None:
        """Test nspawn config with host network."""
        from gaol.models.container import ContainerConfig, NetworkConfig, NetworkMode

        rt = NspawnRuntime()

        config = ContainerConfig(
            name="host-network-container",
            runtime="nspawn",
            network=NetworkConfig(mode=NetworkMode.HOST),
        )

        nspawn_config = rt._generate_nspawn_config(config)
        assert "Private=no" in nspawn_config


class TestLibvirtRuntime:
    """Tests for libvirt/QEMU runtime."""

    def test_runtime_name(self) -> None:
        """Test runtime name property."""
        rt = LibvirtRuntime()
        assert rt.name == "libvirt"

    def test_is_container_runtime(self) -> None:
        """Test that LibvirtRuntime is a ContainerRuntime."""
        rt = LibvirtRuntime()
        assert isinstance(rt, ContainerRuntime)

    def test_libvirt_in_registry(self) -> None:
        """Test that libvirt is available in the runtime registry."""
        rt = get_runtime("libvirt")
        assert isinstance(rt, LibvirtRuntime)

    def test_libvirt_in_available_list(self) -> None:
        """Test that libvirt is in list of available runtimes."""
        runtimes = list_available_runtimes()
        names = [name for name, _ in runtimes]
        assert "libvirt" in names

    def test_domain_xml_generation(self) -> None:
        """Test libvirt domain XML generation."""
        from pathlib import Path

        from gaol.models.container import (
            ContainerConfig,
            NetworkConfig,
            NetworkMode,
            ResourceLimits,
        )

        rt = LibvirtRuntime()

        config = ContainerConfig(
            name="test-vm",
            runtime="libvirt",
            distro="trixie",
            network=NetworkConfig(mode=NetworkMode.SHARED),
            resources=ResourceLimits(memory_mb=2048, cpu_count=2),
        )

        xml = rt._generate_domain_xml(
            "test-vm",
            Path("/path/to/disk.qcow2"),
            Path("/path/to/cloud-init.iso"),
            config,
        )

        assert "<name>test-vm</name>" in xml
        assert "<memory unit='MiB'>2048</memory>" in xml
        assert "<vcpu>2</vcpu>" in xml
        assert "<source file='/path/to/disk.qcow2'/>" in xml
        assert "<source file='/path/to/cloud-init.iso'/>" in xml

    def test_bridged_network_xml(self) -> None:
        """Test libvirt XML with bridged network."""
        from pathlib import Path

        from gaol.models.container import ContainerConfig, NetworkConfig, NetworkMode

        rt = LibvirtRuntime()

        config = ContainerConfig(
            name="bridged-vm",
            runtime="libvirt",
            network=NetworkConfig(mode=NetworkMode.BRIDGED),
        )

        xml = rt._generate_domain_xml(
            "bridged-vm",
            Path("/path/to/disk.qcow2"),
            Path("/path/to/cloud-init.iso"),
            config,
        )
        assert 'source bridge="br0"' in xml

    def test_host_network_xml(self) -> None:
        """Test libvirt XML with host/macvtap network."""
        from pathlib import Path

        from gaol.models.container import ContainerConfig, NetworkConfig, NetworkMode

        rt = LibvirtRuntime()

        config = ContainerConfig(
            name="host-vm",
            runtime="libvirt",
            network=NetworkConfig(mode=NetworkMode.HOST),
        )

        xml = rt._generate_domain_xml(
            "host-vm",
            Path("/path/to/disk.qcow2"),
            Path("/path/to/cloud-init.iso"),
            config,
        )
        assert 'type="direct"' in xml
        assert 'mode="passthrough"' in xml
