//! Validate the PUBLIC product API (`Image::start` → `Vm::exec`) on the KVM
//! backend — the same `supermachine::{Image, Vm, VmConfig}` surface the napi
//! bindings use, now backed by `crate::kvm` on Linux/x86_64.
//!
//! Usage:
//!   kvm_api <image_dir>
//!
//! where <image_dir> contains a `metadata.json` with:
//!   { "backend": "kvm",
//!     "kvm_kernel": "/boot/vmlinuz",
//!     "kvm_initrd": "/path/to/agent.cpio",
//!     "memory_mib": 512, "vcpus": 1 }
//!
//! It loads the image, starts a VM through the public API, execs a command in
//! the guest via the agent (over vsock), prints the result, and stops the VM.

#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
fn main() {
    use std::time::Duration;
    let dir = std::env::args()
        .nth(1)
        .expect("usage: kvm_api <image_dir-with-metadata.json>");

    let image = supermachine::Image::from_snapshot(&dir).expect("Image::from_snapshot");
    eprintln!("=== loaded KVM image from {dir}; starting VM via public API ===");
    let vm = image
        .start(&supermachine::VmConfig::new())
        .expect("Image::start");

    // Let the guest boot and the exec agent come up on AF_VSOCK 1028.
    std::thread::sleep(Duration::from_millis(6000));

    let out = vm
        .exec_builder()
        .argv(["/bin/busybox", "echo", "API_EXEC_OK"])
        .output()
        .expect("Vm::exec output");
    eprintln!(
        "=== [start] EXEC: success={} stdout={:?} ===",
        out.success(),
        String::from_utf8_lossy(&out.stdout).trim_end()
    );
    vm.stop().expect("Vm::stop");
    eprintln!("=== [start] VM stopped cleanly ===");

    // 2) Image::acquire → PooledVm (Deref<Vm>); drops back / tears down.
    {
        let pooled = image.acquire().expect("Image::acquire");
        std::thread::sleep(Duration::from_millis(6000));
        let out = pooled
            .exec_builder()
            .argv(["/bin/busybox", "echo", "ACQUIRE_OK"])
            .output()
            .expect("acquire exec");
        eprintln!(
            "=== [acquire] EXEC: success={} stdout={:?} ===",
            out.success(),
            String::from_utf8_lossy(&out.stdout).trim_end()
        );
        // pooled drops here → VM stops.
    }
    eprintln!("=== [acquire] PooledVm dropped ===");

    // 3) Explicit Pool: image.pool().build() → pool.acquire().
    {
        let pool = image.pool().build().expect("PoolBuilder::build");
        let pooled = pool.acquire().expect("Pool::acquire");
        std::thread::sleep(Duration::from_millis(6000));
        let out = pooled
            .exec_builder()
            .argv(["/bin/busybox", "echo", "POOL_OK"])
            .output()
            .expect("pool exec");
        eprintln!(
            "=== [pool] EXEC: success={} stdout={:?} ===",
            out.success(),
            String::from_utf8_lossy(&out.stdout).trim_end()
        );
        drop(pooled);
        pool.shutdown();
    }
    eprintln!("=== [pool] done ===");

    // 4) Snapshot → Image → restore → exec on the RESTORED VM.
    {
        let vm = image
            .start(&supermachine::VmConfig::new())
            .expect("start for snapshot");
        std::thread::sleep(Duration::from_millis(6000));
        let snap_dir = format!("{dir}/snap2");
        let image2 = vm.snapshot(&snap_dir).expect("Vm::snapshot"); // consumes vm
        eprintln!("=== [snapshot] captured restorable Image at {snap_dir} ===");

        let vm2 = image2
            .start(&supermachine::VmConfig::new())
            .expect("start restored image");
        // Restore is ~ms and the agent was already up in the snapshot.
        std::thread::sleep(Duration::from_millis(2000));
        let out = vm2
            .exec_builder()
            .argv(["/bin/busybox", "echo", "RESTORE_OK"])
            .output()
            .expect("restored exec");
        eprintln!(
            "=== [snapshot] restored EXEC: success={} stdout={:?} ===",
            out.success(),
            String::from_utf8_lossy(&out.stdout).trim_end()
        );
        vm2.stop().expect("stop restored");
    }

    eprintln!("=== all public-API paths (start/acquire/pool/snapshot) exercised on KVM ===");
}

#[cfg(not(all(target_os = "linux", target_arch = "x86_64")))]
fn main() {
    eprintln!("kvm_api is Linux/x86_64 only");
}
