import time
import subprocess
from pathlib import Path
from pathlib import Path
import paramiko
from vncdotool import api as vnc_api

from vagary.schemas import Machine


class MachineManager:
    def __init__(self, config: Machine):
        self.config = config or {}

        self.box = self.config.box
        self.memory = self.config.memory
        self.cpus = 2
        self.vnc_port = 5900
        self.vnc_host = "127.0.0.1"

        self.temp_dir = Path("./tmp")
        self.temp_dir.mkdir(exist_ok=True)

        self.work_dir = self.temp_dir
        self.vagrantfile_path = self.work_dir / "Vagrantfile"

        self.ssh_client = None
        self.vnc_client = None


    def create_vagrantfile(self):
        vagrantfile_content = f'''# -*- mode: ruby -*-
Vagrant.configure("2") do |config|
  config.vm.box = "{self.box}"

  config.vm.provider "libvirt" do |libvirt|
    libvirt.memory = {self.memory}
    libvirt.cpus = {self.cpus}

    libvirt.graphics_type = "vnc"
    libvirt.graphics_port = {self.vnc_port}
    libvirt.graphics_ip = "127.0.0.1"
    libvirt.video_type = "qxl"
    libvirt.video_accel3d = false
  end
end
'''
        self.vagrantfile_path.write_text(vagrantfile_content)
        print(f"> Vagrantfile created: {self.vagrantfile_path}")

    def vagrant_up(self):
        subprocess.run(
            ["vagrant", "destroy", "--force"],
            cwd=self.work_dir,
            check=True
        )
        print(">> Running vagrant up...")
        subprocess.run(
            ["vagrant", "up"],
            cwd=self.work_dir,
            check=True
        )
        print("> Vagrant is up")

    def _get_ssh_config(self):
        result = subprocess.run(
            ["vagrant", "ssh-config"],
            cwd=self.work_dir,
            capture_output=True,
            text=True,
            check=True
        )

        config = {}
        for line in result.stdout.splitlines():
            if line.strip():
                key, value = line.strip().split(None, 1)
                config[key] = value

        return config

    def connect_ssh(self):
        cfg = self._get_ssh_config()

        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect(
            hostname=cfg["HostName"],
            port=int(cfg["Port"]),
            username=cfg["User"],
            key_filename=cfg["IdentityFile"]
        )

        self.ssh_client = client
        print("> SSH connected")

    def connect_vnc(self, password: str | None = None):
        addr = f"{self.vnc_host}"
        self.vnc_client = vnc_api.connect(addr, password=password)
        time.sleep(0.5)
        print("> VNC connected")

    def exec(self, command: str):
        if not self.ssh_client:
            raise RuntimeError("SSH not connected")

        stdin, stdout, stderr = self.ssh_client.exec_command(command)
        return stdout.read().decode(), stderr.read().decode()


    def vnc_key(self, key: str):
        self.vnc_client.keyPress(key)

    def vnc_type(self, text: str, delay=0.05):
        for k in text:
            self.vnc_client.keyPress(k)

    def vnc_move(self, x: int, y: int):
        self.vnc_client.mouseMove(x, y)

    def vnc_click(self, x: int, y: int, button=1):
        self.vnc_client.mouseMove(x, y)
        self.vnc_client.mousePress(button)

    def vnc_screenshot(self, path: str):
        if not self.vnc_client:
            raise RuntimeError("VNC not connected")
        self.vnc_client.captureScreen(path)

    def close(self):
        if self.ssh_client:
            self.ssh_client.close()
        if self.vnc_client:
            self.vnc_client.disconnect()
        vnc_api.shutdown()
        print("> Connections closed")
