"""Proxmox API/CLI wrapper service."""

from __future__ import annotations

import asyncio
import json
from typing import Optional


class ProxmoxService:
    """Wrapper for Proxmox qm/pvesh commands."""

    async def get_templates(self) -> list[dict]:
        """Get all VM templates from Proxmox.

        Returns:
            List of template dictionaries with vmid, name, status, etc.
        """
        vms = await self.get_all_vms()
        return [vm for vm in vms if vm.get("template") == 1]

    async def get_all_vms(self) -> list[dict]:
        """Get all VMs and templates from Proxmox.

        Returns:
            List of VM dictionaries.
        """
        try:
            proc = await asyncio.create_subprocess_exec(
                "pvesh",
                "get",
                "/cluster/resources",
                "--type",
                "vm",
                "--output-format",
                "json",
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE,
            )
            stdout, _ = await proc.communicate()

            if proc.returncode == 0:
                return json.loads(stdout.decode())
        except (json.JSONDecodeError, FileNotFoundError):
            pass

        # Fallback to qm list if pvesh fails
        return await self._get_vms_via_qm()

    async def _get_vms_via_qm(self) -> list[dict]:
        """Fallback method using qm list.

        Returns:
            List of VM dictionaries.
        """
        proc = await asyncio.create_subprocess_exec(
            "qm",
            "list",
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )
        stdout, _ = await proc.communicate()

        if proc.returncode != 0:
            return []

        vms = []
        lines = stdout.decode().strip().split("\n")
        # Skip header line
        for line in lines[1:]:
            parts = line.split()
            if len(parts) >= 3:
                vmid = int(parts[0])
                name = parts[1]
                status = parts[2]
                vms.append(
                    {
                        "vmid": vmid,
                        "name": name,
                        "status": status,
                        "template": await self._is_template(vmid),
                    }
                )

        return vms

    async def _is_template(self, vmid: int) -> int:
        """Check if a VMID is a template.

        Args:
            vmid: VM identifier.

        Returns:
            1 if template, 0 if not.
        """
        proc = await asyncio.create_subprocess_exec(
            "qm",
            "config",
            str(vmid),
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )
        stdout, _ = await proc.communicate()

        if proc.returncode == 0:
            config = stdout.decode()
            if "template: 1" in config:
                return 1
        return 0

    async def find_next_vmid(self, start: int = 100) -> int:
        """Find next available VMID.

        Args:
            start: Starting VMID to search from.

        Returns:
            Next available VMID.
        """
        vms = await self.get_all_vms()
        used_ids = {vm["vmid"] for vm in vms}

        vmid = start
        while vmid in used_ids:
            vmid += 1
        return vmid

    async def get_vm_info(self, vmid: int) -> Optional[dict]:
        """Get detailed info for a specific VM.

        Args:
            vmid: VM identifier.

        Returns:
            VM configuration dictionary or None if not found.
        """
        proc = await asyncio.create_subprocess_exec(
            "qm",
            "config",
            str(vmid),
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )
        stdout, _ = await proc.communicate()

        if proc.returncode != 0:
            return None

        config = {}
        for line in stdout.decode().strip().split("\n"):
            if ":" in line:
                key, value = line.split(":", 1)
                config[key.strip()] = value.strip()

        return config

    async def stop_vm(self, vmid: int) -> bool:
        """Stop a running VM.

        Args:
            vmid: VM identifier.

        Returns:
            True if successful, False otherwise.
        """
        proc = await asyncio.create_subprocess_exec(
            "qm",
            "stop",
            str(vmid),
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )
        await proc.communicate()
        return proc.returncode == 0

    async def destroy_vm(self, vmid: int) -> bool:
        """Stop and destroy a VM.

        Args:
            vmid: VM identifier.

        Returns:
            True if successful, False otherwise.
        """
        # Stop first (ignore errors if already stopped)
        await self.stop_vm(vmid)
        await asyncio.sleep(2)

        # Destroy
        proc = await asyncio.create_subprocess_exec(
            "qm",
            "destroy",
            str(vmid),
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )
        await proc.communicate()
        return proc.returncode == 0

    async def vm_exists(self, vmid: int) -> bool:
        """Check if a VM exists.

        Args:
            vmid: VM identifier.

        Returns:
            True if VM exists, False otherwise.
        """
        proc = await asyncio.create_subprocess_exec(
            "qm",
            "status",
            str(vmid),
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
        )
        await proc.communicate()
        return proc.returncode == 0
