"""Tests for :mod:`mgf.vm.core.configurator.network` (pure planners)."""

from __future__ import annotations

import xml.etree.ElementTree as ET

import pytest

from mgf.vm.core.configurator import network
from mgf.vm.core.exceptions import SpecValidationError


def _dom(macs: tuple[str, ...] = ()) -> ET.Element:
    ifaces = "".join(
        f"<interface type='network'>"
        f"<mac address='{m}'/>"
        f"<source network='default'/>"
        f"<model type='virtio'/>"
        f"</interface>"
        for m in macs
    )
    return ET.fromstring(
        f"<domain><name>web</name><uuid>u</uuid><devices>{ifaces}</devices></domain>"
    )


class TestPlanAdd:
    def test_happy_path(self) -> None:
        change = network.plan_add(_dom(), network="default", mac="52:54:00:aa:bb:cc")
        assert "nic added" in change.summary
        assert "52:54:00:aa:bb:cc" in change.new_xml
        assert change.requires_shutdown is False

    def test_duplicate_mac_rejected(self) -> None:
        with pytest.raises(SpecValidationError, match="already exists"):
            network.plan_add(
                _dom(("52:54:00:aa:bb:cc",)),
                network="default",
                mac="52:54:00:aa:bb:cc",
            )

    def test_bad_mac_rejected(self) -> None:
        with pytest.raises(SpecValidationError, match="invalid MAC"):
            network.plan_add(_dom(), network="default", mac="not-a-mac")

    def test_auto_mac_when_none(self) -> None:
        change = network.plan_add(_dom(), network="default")
        assert "nic added" in change.summary
        assert "<mac" not in change.new_xml


class TestPlanRemove:
    def test_happy_path(self) -> None:
        change = network.plan_remove(_dom(("52:54:00:aa:bb:cc",)), mac="52:54:00:aa:bb:cc")
        assert "nic removed" in change.summary
        assert "52:54:00:aa:bb:cc" not in change.new_xml

    def test_missing_mac(self) -> None:
        with pytest.raises(SpecValidationError, match="no NIC with"):
            network.plan_remove(_dom(), mac="52:54:00:aa:bb:cc")

    def test_bad_mac_rejected(self) -> None:
        with pytest.raises(SpecValidationError, match="invalid MAC"):
            network.plan_remove(_dom(), mac="zz")

    def test_no_devices_element(self) -> None:
        dom = ET.fromstring("<domain><name>web</name></domain>")
        with pytest.raises(SpecValidationError, match="no <devices>"):
            network.plan_remove(dom, mac="52:54:00:aa:bb:cc")
