import os
import signal
import subprocess
import time
from pathlib import Path

from vagary.providers.base import BaseProvider

_PIDFILE = Path("./tmp/qemu.pid")


class QemuProvider(BaseProvider):
    """
    Launches VM via qemu-system-x86_64 -enable-kvm.
    """

    def __init__(
        self,
        disk_image: str,
        disk_format: str = "raw",
        memory: int = 8096,
        cpus: int = 2,
        ssh_user: str | None = None,
        ssh_password: str | None = None,
        ssh_key: str | None = None,
        vnc_port: int = 5900,
        ssh_port: int = 2222,
    ):
        self.disk_image = disk_image
        self.disk_format = disk_format
        self.memory = memory
        self.cpus = cpus
        self.ssh_user = ssh_user
        self.ssh_password = ssh_password
        self.ssh_key = ssh_key
        self.vnc_host = "127.0.0.1"
        self.vnc_port = vnc_port
        self.ssh_port = ssh_port

        _PIDFILE.parent.mkdir(exist_ok=True)

    def start(self) -> None:
        self.stop()

        # VNC display :N = port 5900+N
        vnc_display = self.vnc_port - 5900
        cmd = [
            "qemu-system-x86_64",
            "-enable-kvm",
            "-m", str(self.memory),
            "-smp", str(self.cpus),
            "-drive", f"file={self.disk_image},format={self.disk_format},if=virtio",
            "-netdev", f"user,id=net0,hostfwd=tcp:127.0.0.1:{self.ssh_port}-:22",
            "-device", "virtio-net-pci,netdev=net0",
            "-display", f"vnc=127.0.0.1:{vnc_display}",
            "-pidfile", str(_PIDFILE.resolve()),
            "-daemonize",
        ]
        print(f">> Starting QEMU/KVM: {self.disk_image}")
        subprocess.run(cmd, check=True)
        print(f"> QEMU started (VNC :{self.vnc_port}, SSH 127.0.0.1:{self.ssh_port})")

    def stop(self) -> None:
        if not _PIDFILE.exists():
            return
        try:
            pid = int(_PIDFILE.read_text().strip())
            os.kill(pid, signal.SIGTERM)
            time.sleep(1)
        except (ProcessLookupError, ValueError):
            pass
        _PIDFILE.unlink(missing_ok=True)

    def get_ssh_config(self) -> dict | None:
        if self.ssh_user is None:
            return None
        return {
            "HostName": "127.0.0.1",
            "Port": str(self.ssh_port),
            "User": self.ssh_user,
            "IdentityFile": self.ssh_key,
            "Password": self.ssh_password,
        }
