package model

// VMHandles captures the transient, per-boot kernel/process handles
// that banger obtains while starting a VM and releases when stopping
// it. Unlike VMRuntime (durable spec + identity + derived paths),
// VMHandles is the authoritative live-handle view while the daemon is
// up. On restart, the daemon rebuilds it from the OS plus the per-VM
// scratch file; teardown-critical fields are also mirrored onto
// VMRuntime so cleanup can still proceed if that scratch file is
// missing or corrupt.
//
// The daemon keeps an in-memory cache keyed by VM ID. Lifecycle
// transitions update the cache and a small `handles.json` scratch
// file in the VM's state directory; daemon startup reconciles
// by loading that file and verifying each handle against the live
// OS state. If anything is stale the VM is marked stopped and the
// cache entry is dropped.
//
// VMHandles itself never appears in the `vms` SQLite rows. Some fields
// are mirrored onto VMRuntime as crash-recovery fallback state, but the
// cache + scratch file remain the canonical live source.
type VMHandles struct {
	// PID is the firecracker process PID. Zero means "not running
	// (from our perspective)". Always verifiable via
	// /proc/<pid>/cmdline matching the api socket path.
	PID int `json:"pid,omitempty"`

	// TapDevice is the kernel tap interface name (e.g. "tap-fc-0001")
	// bound to the VM's virtio-net. Released on stop.
	TapDevice string `json:"tap_device,omitempty"`

	// BaseLoop and COWLoop are the two loop devices backing the
	// dm-snapshot layer (read-only base = rootfs; read-write overlay
	// = per-VM COW file). Released via losetup -d on stop.
	BaseLoop string `json:"base_loop,omitempty"`
	COWLoop  string `json:"cow_loop,omitempty"`

	// DMName is the device-mapper target name; deterministic from the
	// VM ID (see dmsnap.SnapshotName). DMDev is the corresponding
	// /dev/mapper/<name> path. Torn down by `dmsetup remove` on stop.
	DMName string `json:"dm_name,omitempty"`
	DMDev  string `json:"dm_dev,omitempty"`
}

// IsZero reports whether every handle field is unset. Useful as a
// cheap "this VM has no kernel/process resources held on our behalf"
// check.
func (h VMHandles) IsZero() bool {
	return h.PID == 0 && h.TapDevice == "" && h.BaseLoop == "" && h.COWLoop == "" && h.DMName == "" && h.DMDev == ""
}
