"""Unit tests for ``LibvirtVmSpec.from_core`` — the canonical mapper (D-G12).

Covers: neutral-field mapping, disk/nic mapping, each ``libvirt/*``
metadata-override key, defaults-when-absent, defensive type parsing, and
the determinism contract (same ``(spec, metadata)`` → byte-identical XML).
"""

from __future__ import annotations

from mgf.vm.core.contracts import DiskSpec as CoreDiskSpec
from mgf.vm.core.contracts import NicSpec as CoreNicSpec
from mgf.vm.core.contracts import VmSpec
from mgf.vm.core.domain import IsolationLevel

from mgf.vm.libvirt._spec import (
    DEFAULT_BALLOON,
    DEFAULT_CPU_MODEL,
    DEFAULT_DISK_BUS,
    DEFAULT_DISK_CACHE,
    DEFAULT_DISPLAY,
    DEFAULT_FIRMWARE,
    DEFAULT_HUGEPAGES,
    DEFAULT_SECURE_BOOT,
    KEY_BALLOON,
    KEY_CPU_MODEL,
    KEY_CPU_PINNING,
    KEY_DISK_BUS,
    KEY_DISK_CACHE,
    KEY_DISPLAY,
    KEY_FIRMWARE,
    KEY_HUGEPAGES,
    KEY_MEMORY_MAX_BYTES,
    KEY_SECURE_BOOT,
    KEY_VCPUS_MAX,
    LibvirtVmSpec,
)
from mgf.vm.libvirt._xml.generate import vmspec_to_xml

GIB = 1024 * 1024 * 1024


def _core(**overrides: object) -> VmSpec:
    base = {"name": "vm", "cpu": 2, "memory_bytes": 2 * GIB}
    base.update(overrides)
    return VmSpec(**base)  # type: ignore[arg-type]


# --- neutral field mapping ---------------------------------------------------


def test_neutral_fields_map_directly() -> None:
    lv = LibvirtVmSpec.from_core(_core(name="abc", cpu=8, memory_bytes=7 * GIB))
    assert lv.name == "abc"
    assert lv.vcpus == 8
    assert lv.memory_bytes == 7 * GIB


def test_isolation_maps_directly() -> None:
    lv = LibvirtVmSpec.from_core(_core(isolation=IsolationLevel.STRICT))
    assert lv.isolation is IsolationLevel.STRICT


def test_core_disks_map_with_bus_cache_and_target() -> None:
    core = _core(
        disks=(
            CoreDiskSpec(size_bytes=10 * GIB, format="raw", source="/img/a", readonly=True),
            CoreDiskSpec(size_bytes=5 * GIB),
        )
    )
    lv = LibvirtVmSpec.from_core(core)
    assert len(lv.disks) == 2
    d0, d1 = lv.disks
    assert d0.size_bytes == 10 * GIB
    assert d0.format == "raw"
    assert d0.source_path == "/img/a"
    assert d0.readonly is True
    assert d0.bus == DEFAULT_DISK_BUS
    assert d0.cache == DEFAULT_DISK_CACHE
    # deterministic, index-derived target devs
    assert d0.target == "vda"
    assert d1.target == "vdb"


def test_core_nics_map_directly() -> None:
    core = _core(nics=(CoreNicSpec(network="br0", model="e1000", mac="52:54:00:00:00:01"),))
    lv = LibvirtVmSpec.from_core(core)
    assert len(lv.nics) == 1
    n = lv.nics[0]
    assert n.network == "br0"
    assert n.model == "e1000"
    assert n.mac == "52:54:00:00:00:01"


def test_no_nics_yields_empty_tuple() -> None:
    # from_core maps exactly the core nics — no synthesized default NIC.
    assert LibvirtVmSpec.from_core(_core()).nics == ()


# --- defaults when metadata absent -------------------------------------------


def test_defaults_when_metadata_absent() -> None:
    lv = LibvirtVmSpec.from_core(_core())
    assert lv.firmware == DEFAULT_FIRMWARE
    assert lv.secure_boot is DEFAULT_SECURE_BOOT
    assert lv.cpu_model == DEFAULT_CPU_MODEL
    assert lv.cpu_pinning is None
    assert lv.vcpus_max is None
    assert lv.hugepages is DEFAULT_HUGEPAGES
    assert lv.balloon is DEFAULT_BALLOON
    assert lv.display == DEFAULT_DISPLAY
    assert lv.memory_max_bytes is None


# --- each libvirt/* metadata override key ------------------------------------


def test_override_firmware() -> None:
    lv = LibvirtVmSpec.from_core(_core(metadata={KEY_FIRMWARE: "uefi"}))
    assert lv.firmware == "uefi"


def test_override_secure_boot() -> None:
    lv = LibvirtVmSpec.from_core(_core(metadata={KEY_SECURE_BOOT: "true"}))
    assert lv.secure_boot is True


def test_override_cpu_model() -> None:
    lv = LibvirtVmSpec.from_core(_core(metadata={KEY_CPU_MODEL: "EPYC"}))
    assert lv.cpu_model == "EPYC"


def test_override_cpu_pinning() -> None:
    lv = LibvirtVmSpec.from_core(_core(metadata={KEY_CPU_PINNING: "0-3"}))
    assert lv.cpu_pinning == "0-3"


def test_override_vcpus_max() -> None:
    lv = LibvirtVmSpec.from_core(_core(metadata={KEY_VCPUS_MAX: "16"}))
    assert lv.vcpus_max == 16


def test_override_hugepages() -> None:
    lv = LibvirtVmSpec.from_core(_core(metadata={KEY_HUGEPAGES: "yes"}))
    assert lv.hugepages is True


def test_override_balloon_off() -> None:
    lv = LibvirtVmSpec.from_core(_core(metadata={KEY_BALLOON: "false"}))
    assert lv.balloon is False


def test_override_display() -> None:
    lv = LibvirtVmSpec.from_core(_core(metadata={KEY_DISPLAY: "vnc"}))
    assert lv.display == "vnc"


def test_override_disk_bus_and_cache() -> None:
    core = _core(
        metadata={KEY_DISK_BUS: "scsi", KEY_DISK_CACHE: "writeback"},
        disks=(CoreDiskSpec(size_bytes=GIB),),
    )
    lv = LibvirtVmSpec.from_core(core)
    assert lv.disks[0].bus == "scsi"
    assert lv.disks[0].cache == "writeback"


def test_override_memory_max_bytes() -> None:
    lv = LibvirtVmSpec.from_core(_core(metadata={KEY_MEMORY_MAX_BYTES: str(8 * GIB)}))
    assert lv.memory_max_bytes == 8 * GIB


# --- defensive type parsing --------------------------------------------------


def test_bool_parsing_variants() -> None:
    for raw, expected in [
        ("1", True),
        ("ON", True),
        ("Yes", True),
        ("0", False),
        ("off", False),
        ("no", False),
    ]:
        lv = LibvirtVmSpec.from_core(_core(metadata={KEY_HUGEPAGES: raw}))
        assert lv.hugepages is expected, raw


def test_bool_garbage_falls_back_to_default() -> None:
    # balloon defaults True; a garbage value must not flip or raise.
    lv = LibvirtVmSpec.from_core(_core(metadata={KEY_BALLOON: "maybe"}))
    assert lv.balloon is DEFAULT_BALLOON


def test_int_garbage_falls_back_to_default() -> None:
    lv = LibvirtVmSpec.from_core(_core(metadata={KEY_VCPUS_MAX: "lots"}))
    assert lv.vcpus_max is None


def test_int_whitespace_tolerated() -> None:
    lv = LibvirtVmSpec.from_core(_core(metadata={KEY_VCPUS_MAX: "  4 "}))
    assert lv.vcpus_max == 4


# --- determinism -------------------------------------------------------------


def test_from_core_is_deterministic() -> None:
    core = _core(
        metadata={KEY_FIRMWARE: "uefi", KEY_VCPUS_MAX: "4", KEY_HUGEPAGES: "1"},
        disks=(CoreDiskSpec(size_bytes=GIB), CoreDiskSpec(size_bytes=2 * GIB)),
        nics=(CoreNicSpec(network="br0"),),
    )
    assert LibvirtVmSpec.from_core(core) == LibvirtVmSpec.from_core(core)


def test_metadata_shim_is_empty() -> None:
    # Libvirt tuning has already been consumed into typed fields; the
    # back-compat ``metadata`` accessor reports an empty mapping.
    assert LibvirtVmSpec.from_core(_core(metadata={KEY_FIRMWARE: "uefi"})).metadata == {}


def test_evolve_overrides_fields() -> None:
    lv = LibvirtVmSpec.from_core(_core()).evolve(uuid="abc", description="d")
    assert lv.uuid == "abc"
    assert lv.description == "d"


def test_from_core_renders_byte_identical_xml() -> None:
    core = _core(
        metadata={KEY_DISPLAY: "vnc", KEY_DISK_BUS: "scsi"},
        disks=(CoreDiskSpec(size_bytes=GIB),),
        nics=(CoreNicSpec(mac="52:54:00:00:00:09"),),
    )
    a = vmspec_to_xml(LibvirtVmSpec.from_core(core))
    b = vmspec_to_xml(LibvirtVmSpec.from_core(core))
    assert a == b
