"""CPU-related fix executors."""

from __future__ import annotations

import xml.etree.ElementTree as ET  # noqa: TC003
from typing import TYPE_CHECKING, Any

from mgf.vm.core.security.isolation.types import isolation_fix

if TYPE_CHECKING:
    from mgf.vm.core.common.progress import ProgressReporter


__all__ = ["cpu_generic_topology", "cpu_swap_to_host_model"]


@isolation_fix("cpu.swap_to_host_model")
def cpu_swap_to_host_model(
    *,
    target: ET.ElementTree,
    reporter: ProgressReporter,
    dry_run: bool = False,
    **_kw: Any,
) -> None:
    """Replace ``<cpu mode='host-passthrough'>`` with ``mode='host-model'``.

    Idempotent: a CPU element already in ``host-model`` (or any
    non-``host-passthrough`` mode) is left alone.
    """
    root = target.getroot()
    cpu = root.find("cpu") if root is not None else None
    if cpu is None:
        reporter.report("cpu.swap_to_host_model: no <cpu> element")
        return
    if cpu.get("mode") != "host-passthrough":
        reporter.report("cpu.swap_to_host_model: already satisfied")
        return
    if dry_run:
        reporter.report(
            "cpu.swap_to_host_model: (dry-run) would set mode='host-model'",
        )
        return
    cpu.set("mode", "host-model")
    reporter.report("cpu.swap_to_host_model: rewrote mode='host-model'")


@isolation_fix("cpu.generic_topology")
def cpu_generic_topology(
    *,
    target: ET.ElementTree,
    reporter: ProgressReporter,
    dry_run: bool = False,
    **_kw: Any,
) -> None:
    """Strip the ``<topology>`` element under ``<cpu>``.

    Without an explicit topology, qemu defaults to a generic
    1-socket layout — which is what we want for malware analysis
    (no host fingerprint).
    """
    root = target.getroot()
    cpu = root.find("cpu") if root is not None else None
    if cpu is None:
        reporter.report("cpu.generic_topology: no <cpu> element")
        return
    topology = cpu.find("topology")
    if topology is None:
        reporter.report("cpu.generic_topology: already satisfied")
        return
    if dry_run:
        reporter.report("cpu.generic_topology: (dry-run) would remove <topology>")
        return
    cpu.remove(topology)
    reporter.report("cpu.generic_topology: removed <topology>")
