"""Tests for :mod:`mgf.vm.core.configurator.cpu` (pure planner)."""

from __future__ import annotations

import xml.etree.ElementTree as ET

import pytest

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


def _dom(vcpu_max: int = 4, vcpu_current: int = 2, model: str = "host-passthrough") -> ET.Element:
    return ET.fromstring(
        f"<domain><name>web</name><uuid>u</uuid>"
        f"<vcpu current='{vcpu_current}'>{vcpu_max}</vcpu>"
        f"<cpu><model>{model}</model></cpu>"
        f"</domain>"
    )


class TestPlan:
    def test_grow_current_vcpus_is_hotpluggable(self) -> None:
        change = cpu.plan(_dom(), vcpus=4)
        assert "vcpus 2 -> 4" in change.summary
        assert change.requires_shutdown is False
        assert change.subsystem == "cpu"

    def test_grow_max_requires_shutdown(self) -> None:
        change = cpu.plan(_dom(), vcpus_max=8)
        assert "vcpus_max 4 -> 8" in change.summary
        assert change.requires_shutdown is True

    def test_model_change_requires_shutdown(self) -> None:
        change = cpu.plan(_dom(model="Nehalem"), model="host-passthrough")
        assert change.requires_shutdown is True
        assert "cpu_model" in change.summary

    def test_noop_plan(self) -> None:
        change = cpu.plan(_dom(), vcpus=2)
        assert change.summary == "no change"
        assert change.requires_shutdown is False

    def test_old_xml_captured_before_mutation(self) -> None:
        change = cpu.plan(_dom(), vcpus=4)
        assert 'current="2"' in change.old_xml or "current='2'" in change.old_xml
        assert 'current="4"' in change.new_xml or "current='4'" in change.new_xml

    def test_vcpus_exceeds_max_rejected(self) -> None:
        with pytest.raises(SpecValidationError, match="must be <="):
            cpu.plan(_dom(), vcpus=8)

    def test_negative_vcpus_rejected(self) -> None:
        with pytest.raises(SpecValidationError, match="must be >= 1"):
            cpu.plan(_dom(), vcpus=0)

    def test_negative_vcpus_max_rejected(self) -> None:
        with pytest.raises(SpecValidationError, match="must be >= 1"):
            cpu.plan(_dom(), vcpus_max=0)
