"""``strip.*`` executors — remove leak-path elements from a domain XML.

Eleven executors covering every BLOCKING + AUTO_FIX shared-channel
device, hostdev, vsock, macvtap interface, and PCI-passthrough
interface. Each is idempotent and dry-run-aware via the shared
:func:`_helpers.remove_devices_matching` helper.

Mapping back to the §5 catalogue: every BLOCKING finding whose
``fix_executor`` starts with ``strip.`` resolves here.
"""

from __future__ import annotations

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

from mgf.vm.core.security.isolation.fixes._helpers import remove_devices_matching
from mgf.vm.core.security.isolation.types import isolation_fix

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


__all__ = [
    "strip_channel_guest_agent",
    "strip_channel_spice_clipboard",
    "strip_filesystem",
    "strip_hostdev_mdev",
    "strip_hostdev_pci",
    "strip_hostdev_usb",
    "strip_iface_macvtap",
    "strip_iface_passthrough",
    "strip_redirdev",
    "strip_smartcard",
    "strip_vsock",
]


# ---------------------------------------------------------------------------
# Shared channels
# ---------------------------------------------------------------------------


@isolation_fix("strip.filesystem")
def strip_filesystem(
    *,
    target: ET.ElementTree,
    reporter: ProgressReporter,
    dry_run: bool = False,
    **_kw: Any,
) -> None:
    """Remove every ``<filesystem>`` element (virtio-fs / 9p shares)."""
    remove_devices_matching(
        target,
        tag="filesystem",
        reporter=reporter,
        dry_run=dry_run,
        fix_id="strip.filesystem",
    )


def _channel_target_starts_with(prefix: str) -> Any:
    def _predicate(elem: ET.Element) -> bool:
        target = elem.find("target")
        if target is None:
            return False
        return target.get("name", "").startswith(prefix)

    return _predicate


@isolation_fix("strip.channel.guest_agent")
def strip_channel_guest_agent(
    *,
    target: ET.ElementTree,
    reporter: ProgressReporter,
    dry_run: bool = False,
    **_kw: Any,
) -> None:
    """Remove every ``<channel>`` whose target name starts with
    ``org.qemu.guest_agent``."""
    remove_devices_matching(
        target,
        tag="channel",
        predicate=_channel_target_starts_with("org.qemu.guest_agent"),
        reporter=reporter,
        dry_run=dry_run,
        fix_id="strip.channel.guest_agent",
    )


@isolation_fix("strip.channel.spice_clipboard")
def strip_channel_spice_clipboard(
    *,
    target: ET.ElementTree,
    reporter: ProgressReporter,
    dry_run: bool = False,
    **_kw: Any,
) -> None:
    """Remove every ``<channel>`` whose target name starts with
    ``com.redhat.spice``."""
    remove_devices_matching(
        target,
        tag="channel",
        predicate=_channel_target_starts_with("com.redhat.spice"),
        reporter=reporter,
        dry_run=dry_run,
        fix_id="strip.channel.spice_clipboard",
    )


@isolation_fix("strip.redirdev")
def strip_redirdev(
    *,
    target: ET.ElementTree,
    reporter: ProgressReporter,
    dry_run: bool = False,
    **_kw: Any,
) -> None:
    """Remove every ``<redirdev>`` (USB redirection)."""
    remove_devices_matching(
        target,
        tag="redirdev",
        reporter=reporter,
        dry_run=dry_run,
        fix_id="strip.redirdev",
    )


@isolation_fix("strip.smartcard")
def strip_smartcard(
    *,
    target: ET.ElementTree,
    reporter: ProgressReporter,
    dry_run: bool = False,
    **_kw: Any,
) -> None:
    """Remove every ``<smartcard>`` passthrough."""
    remove_devices_matching(
        target,
        tag="smartcard",
        reporter=reporter,
        dry_run=dry_run,
        fix_id="strip.smartcard",
    )


@isolation_fix("strip.vsock")
def strip_vsock(
    *,
    target: ET.ElementTree,
    reporter: ProgressReporter,
    dry_run: bool = False,
    **_kw: Any,
) -> None:
    """Remove the ``<vsock>`` device."""
    remove_devices_matching(
        target,
        tag="vsock",
        reporter=reporter,
        dry_run=dry_run,
        fix_id="strip.vsock",
    )


# ---------------------------------------------------------------------------
# Hostdev passthrough
# ---------------------------------------------------------------------------


def _hostdev_of_type(dev_type: str) -> Any:
    def _predicate(elem: ET.Element) -> bool:
        return elem.get("mode") == "subsystem" and elem.get("type") == dev_type

    return _predicate


@isolation_fix("strip.hostdev.pci")
def strip_hostdev_pci(
    *,
    target: ET.ElementTree,
    reporter: ProgressReporter,
    dry_run: bool = False,
    **_kw: Any,
) -> None:
    """Remove every ``<hostdev mode='subsystem' type='pci'>``."""
    remove_devices_matching(
        target,
        tag="hostdev",
        predicate=_hostdev_of_type("pci"),
        reporter=reporter,
        dry_run=dry_run,
        fix_id="strip.hostdev.pci",
    )


@isolation_fix("strip.hostdev.usb")
def strip_hostdev_usb(
    *,
    target: ET.ElementTree,
    reporter: ProgressReporter,
    dry_run: bool = False,
    **_kw: Any,
) -> None:
    """Remove every ``<hostdev mode='subsystem' type='usb'>``."""
    remove_devices_matching(
        target,
        tag="hostdev",
        predicate=_hostdev_of_type("usb"),
        reporter=reporter,
        dry_run=dry_run,
        fix_id="strip.hostdev.usb",
    )


@isolation_fix("strip.hostdev.mdev")
def strip_hostdev_mdev(
    *,
    target: ET.ElementTree,
    reporter: ProgressReporter,
    dry_run: bool = False,
    **_kw: Any,
) -> None:
    """Remove every ``<hostdev mode='subsystem' type='mdev'>``."""
    remove_devices_matching(
        target,
        tag="hostdev",
        predicate=_hostdev_of_type("mdev"),
        reporter=reporter,
        dry_run=dry_run,
        fix_id="strip.hostdev.mdev",
    )


# ---------------------------------------------------------------------------
# Network interfaces (macvtap + PCI-passthrough NICs)
# ---------------------------------------------------------------------------


@isolation_fix("strip.iface.macvtap")
def strip_iface_macvtap(
    *,
    target: ET.ElementTree,
    reporter: ProgressReporter,
    dry_run: bool = False,
    **_kw: Any,
) -> None:
    """Remove every ``<interface type='direct'>`` (macvtap)."""

    def _is_macvtap(elem: ET.Element) -> bool:
        return elem.get("type") == "direct"

    remove_devices_matching(
        target,
        tag="interface",
        predicate=_is_macvtap,
        reporter=reporter,
        dry_run=dry_run,
        fix_id="strip.iface.macvtap",
    )


@isolation_fix("strip.iface.passthrough")
def strip_iface_passthrough(
    *,
    target: ET.ElementTree,
    reporter: ProgressReporter,
    dry_run: bool = False,
    **_kw: Any,
) -> None:
    """Remove every ``<hostdev>`` whose alias suggests a NIC role.

    Pairs with the network-side ``net.no_passthrough_nic`` check,
    which only fires on NIC-aliased PCI hostdevs (the broader
    ``hostdev.no_pci`` catches them all). Stripping by alias keeps
    legitimate non-NIC PCI passthroughs intact for users who explicitly
    set ``isolation=off``.
    """

    def _is_nic_aliased(elem: ET.Element) -> bool:
        if elem.get("mode") != "subsystem" or elem.get("type") != "pci":
            return False
        alias = elem.find("alias")
        if alias is None:
            return False
        name = alias.get("name", "")
        return name.startswith("net") or "ethernet" in name.lower()

    remove_devices_matching(
        target,
        tag="hostdev",
        predicate=_is_nic_aliased,
        reporter=reporter,
        dry_run=dry_run,
        fix_id="strip.iface.passthrough",
    )
