"""``configurator/shares`` — virtiofs / 9p ``<filesystem>`` edits (pure planners).

Share mounts let a VM see a host directory. libvirt exposes two
transports: ``virtiofs`` (modern, requires vhost-user-fs and shared
memory-backing on x86) and ``9p`` (legacy). Neither is hotpluggable in
practice, so every share edit flags ``requires_shutdown=True``.

**Pure core.** Each planner accepts an *already-parsed*
:class:`xml.etree.ElementTree.Element`; the ``apply_*`` halves stay in
the adapter (``mgf-vm``).
"""

from __future__ import annotations

import xml.etree.ElementTree as ET

from mgf.vm.core.configurator.types import ConfigChange
from mgf.vm.core.configurator.xml_helpers import ensure, serialize_domain_xml
from mgf.vm.core.exceptions import SpecValidationError

SUBSYSTEM = "share"

_VALID_DRIVERS = {"virtiofs", "9p"}


def plan_add(
    domain: ET.Element,
    *,
    source: str,
    target: str,
    driver: str = "virtiofs",
    readonly: bool = False,
) -> ConfigChange:
    """Attach a new ``<filesystem>`` element to the injected tree."""
    if driver not in _VALID_DRIVERS:
        raise SpecValidationError([f"share driver must be one of {sorted(_VALID_DRIVERS)}"])
    if not source or not target:
        raise SpecValidationError(["source and target are both required for a share"])

    old_xml = serialize_domain_xml(domain)
    devices = ensure(domain, "devices")

    for fs in devices.findall("filesystem"):
        target_el = fs.find("target")
        if target_el is not None and target_el.get("dir") == target:
            raise SpecValidationError([f"share target {target!r} already exists on domain"])

    fs = ET.SubElement(devices, "filesystem", {"type": "mount"})
    ET.SubElement(fs, "driver", {"type": driver})
    ET.SubElement(fs, "source", {"dir": source})
    ET.SubElement(fs, "target", {"dir": target})
    if readonly:
        ET.SubElement(fs, "readonly")

    return ConfigChange(
        subsystem=SUBSYSTEM,
        summary=f"share added {source} -> {target} ({driver})",
        old_xml=old_xml,
        new_xml=serialize_domain_xml(domain),
        requires_shutdown=True,
    )


def plan_remove(domain: ET.Element, *, target: str) -> ConfigChange:
    """Drop the ``<filesystem>`` with ``target dir == target``."""
    old_xml = serialize_domain_xml(domain)
    devices = domain.find("devices")
    if devices is None:
        raise SpecValidationError(["domain has no <devices> element"])

    for fs in list(devices.findall("filesystem")):
        target_el = fs.find("target")
        if target_el is not None and target_el.get("dir") == target:
            devices.remove(fs)
            return ConfigChange(
                subsystem=SUBSYSTEM,
                summary=f"share removed target={target}",
                old_xml=old_xml,
                new_xml=serialize_domain_xml(domain),
                requires_shutdown=True,
            )

    raise SpecValidationError([f"no share with target {target!r}"])


__all__ = [
    "SUBSYSTEM",
    "plan_add",
    "plan_remove",
]
