"""Infra mixin: low-level shell commands and libvirt XML generation."""

from __future__ import annotations

import subprocess
from pathlib import Path

import structlog

from proxym.virt._config import VMConfig

logger = structlog.get_logger()


class _InfraMixin:
    """Low-level helpers: shell commands and libvirt XML generation."""

    @staticmethod
    def _run(cmd: str, check: bool = True) -> subprocess.CompletedProcess:
        try:
            return subprocess.run(
                cmd.split(), capture_output=True, text=True,
                timeout=30,
            )
        except subprocess.TimeoutExpired:
            return subprocess.CompletedProcess(cmd, 1, "", "timeout")
        except Exception as e:
            return subprocess.CompletedProcess(cmd, 1, "", str(e))

    @staticmethod
    def check_libvirt_available() -> dict:
        """Check if libvirt is available on this system."""
        checks = {}
        for cmd, label in [
            ("virsh version", "libvirt"),
            ("qemu-img --version", "qemu"),
            ("virt-install --version", "virt-install"),
        ]:
            try:
                result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=5)
                checks[label] = result.returncode == 0
            except Exception:
                checks[label] = False
        return checks

    @staticmethod
    def _is_virtiofs_available() -> bool:
        for p in ["/usr/libexec/virtiofsd", "/usr/bin/virtiofsd", "/usr/local/bin/virtiofsd"]:
            if Path(p).exists():
                return True
        # old path on some distros
        return Path("/usr/sbin/virtiofsd").exists()

    def _generate_domain_xml(self, vm: VMConfig) -> str:
        """Generate libvirt domain XML for the VM."""
        filesystem_block = ""
        if vm.code_mount_host and self._is_virtiofs_available():
            filesystem_block = f"""
    <filesystem type='mount' accessmode='passthrough'>
      <driver type='virtiofs'/>
      <source dir='{vm.code_mount_host}'/>
      <target dir='code_share'/>
    </filesystem>"""
        else:
            logger.warning("virtiofs_disabled", code_mount_host=vm.code_mount_host)

        xml = f"""<domain type='kvm'>
  <name>{vm.id}</name>
  <memory unit='MiB'>{vm.memory_mb}</memory>
  <vcpu>{vm.vcpus}</vcpu>

  <os>
    <type arch='x86_64' machine='q35'>hvm</type>
    <boot dev='hd'/>
  </os>

  <features>
    <acpi/><apic/>
  </features>

  <cpu mode='host-passthrough'/>

  <devices>
    <!-- Overlay disk -->
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2'/>
      <source file='{vm.overlay_path}'/>
      <target dev='vda' bus='virtio'/>
    </disk>

    <!-- Network (NAT with port forwards) -->
    <interface type='network'>
      <source network='default'/>
      <model type='virtio'/>
    </interface>

    {filesystem_block}

    <!-- Console -->
    <serial type='pty'><target port='0'/></serial>
    <console type='pty'><target type='serial' port='0'/></console>

    <!-- VGA for GUI tools -->
    <graphics type='spice' autoport='yes'>
      <listen type='address' address='127.0.0.1'/>
    </graphics>
    <video><model type='virtio' heads='1' primary='yes'/></video>
  </devices>
</domain>"""

        xml_path = self.config_dir / f"{vm.id}.xml"
        xml_path.write_text(xml)

        # Define in libvirt
        result = self._run(f"virsh define {xml_path}", check=False)
        if result.returncode != 0:
            raise RuntimeError(f"Failed to define domain in libvirt: {result.stderr}")
        return xml
