"""State mixin: VM status queries and state refresh."""

from __future__ import annotations

import time

from proxym.virt._config import VMConfig, VMStatus
from proxym.virt._enums import VMBackend, VMState


class _StateMixin:
    """VM status queries and state refresh."""

    def get_status(self, vm_id: str) -> VMStatus | None:
        """Get current status of a VM, querying the backend for live state."""
        vm = self.vms.get(vm_id)
        if not vm:
            return None

        if vm.backend == VMBackend.CLONEBOX.value:
            self._refresh_state_clonebox(vm)
        else:
            self._refresh_state_virsh(vm)

        uptime = 0.0
        if vm.state == VMState.RUNNING and vm.last_started_at:
            uptime = time.time() - vm.last_started_at

        ip = self._get_vm_ip(vm.id) if vm.state == VMState.RUNNING else ""

        return VMStatus(
            id=vm.id,
            name=vm.name,
            state=vm.state,
            account_id=vm.account_id,
            tool=vm.tool,
            backend=vm.backend,
            uptime_seconds=uptime,
            code_mount=vm.code_mount_host,
            ip_address=ip,
            # Resource configuration
            memory_mb=vm.memory_mb,
            vcpus=vm.vcpus,
            disk_gb=vm.disk_gb,
            # Timing
            last_started_at=vm.last_started_at,
            created_at=vm.created_at,
        )

    def _refresh_state_clonebox(self, vm: VMConfig) -> None:
        """Update VM state from clonebox health output."""
        cb = self._get_clonebox()
        if not cb:
            return
        health = cb.health(vm.id)
        if not health.success:
            return
        out = health.stdout.lower()
        if "running" in out:
            vm.state = VMState.RUNNING
        elif "stopped" in out or "shut off" in out:
            vm.state = VMState.STOPPED
        elif "paused" in out:
            vm.state = VMState.PAUSED

    def _refresh_state_virsh(self, vm: VMConfig) -> None:
        """Update VM state from virsh domstate."""
        result = self._run(f"virsh domstate {vm.id}", check=False)
        if result.returncode != 0:
            return
        state_str = result.stdout.strip()
        state_map = {
            "running": VMState.RUNNING,
            "shut off": VMState.STOPPED,
            "paused": VMState.PAUSED,
        }
        vm.state = state_map.get(state_str, VMState.ERROR)

    def _get_vm_ip(self, vm_id: str) -> str:
        """Extract VM IP address from virsh DHCP leases."""
        ip_result = self._run(
            f"virsh domifaddr {vm_id} --source agent", check=False
        )
        if ip_result.returncode != 0:
            return ""
        for line in ip_result.stdout.splitlines():
            if "ipv4" in line:
                for p in line.split():
                    if "/" in p and "." in p:
                        return p.split("/")[0]
        return ""

    def list_vms(self) -> list[VMStatus]:
        return [s for vm_id in self.vms if (s := self.get_status(vm_id))]
