//! Close the in-VM builder's RAM/storage-density loop on KVM (component 3 of
//! docs/design/in-vm-builder-2026-06-05.md): build a Dockerfile whose RUN
//! creates a sizable file, then COMMIT the built image to a read-only squashfs
//! and re-bake it as a cold-bootable KVM image. Verify a fresh VM booted from
//! the committed image still has the RUN's output, and compare artifacts:
//!
//!   - snapshot-layer image  = a FULL guest-RAM dump (restore.snap) — carries
//!     the build's files in the guest tmpfs overlay, i.e. inflated RAM.
//!   - committed squashfs     = filesystem only, compressed, read-only, shared
//!     across VMs via the host page cache; boots with an empty tmpfs upper.
//!
//! The committed artifact should be much smaller AND boot to the same FS.

#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
fn dir_size(p: &std::path::Path) -> u64 {
    let mut total = 0;
    if let Ok(rd) = std::fs::read_dir(p) {
        for e in rd.flatten() {
            let m = match e.metadata() {
                Ok(m) => m,
                Err(_) => continue,
            };
            if m.is_dir() {
                total += dir_size(&e.path());
            } else {
                total += m.len();
            }
        }
    }
    total
}

#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
fn main() {
    use std::time::{Duration, Instant};
    use supermachine::{builder, Image, VmConfig};

    let mib = 64u64; // size of the RUN-created blob
    let dockerfile = format!(
        "FROM alpine\n\
         RUN mkdir -p /data && dd if=/dev/urandom of=/data/blob bs=1M count={mib} 2>/dev/null \
             && sha256sum /data/blob | cut -d' ' -f1 > /data/blob.sha \
             && echo committed-density-ok > /data/marker\n"
    );
    let df = builder::parse(&dockerfile).expect("parse");

    let ctx = std::env::temp_dir().join("sm-density-ctx");
    let _ = std::fs::create_dir_all(&ctx);
    let build_dest = std::env::temp_dir().join("sm-density-build");
    let _ = std::fs::remove_dir_all(&build_dest);
    let commit_dir = std::env::temp_dir().join("sm-density-commit");
    let _ = std::fs::remove_dir_all(&commit_dir);

    let base = Image::from_oci("alpine").expect("from_oci");

    eprintln!("=== build (snapshot-layer) ===");
    let t0 = Instant::now();
    let out = builder::build_linear(&df, &base, &ctx, &build_dest).expect("build_linear");
    eprintln!("build took {:?}", t0.elapsed());

    // The snapshot-layer image's on-disk size: the whole build_dest (full
    // guest-RAM dump restore.snap + metadata + assets) and the RAM dump alone.
    let snap_bytes = dir_size(&build_dest);
    let restore_snap_bytes = std::fs::metadata(build_dest.join("restore.snap"))
        .map(|m| m.len())
        .unwrap_or(0);

    eprintln!("=== verify snapshot-layer image has the RUN output ===");
    let vm = out.image.start(&VmConfig::new()).expect("start snap-layer");
    std::thread::sleep(Duration::from_millis(4000));
    let o = vm
        .exec_builder()
        .argv([
            "/bin/sh",
            "-c",
            "cat /data/marker; stat -c%s /data/blob; \
             if [ \"$(sha256sum /data/blob | cut -d' ' -f1)\" = \"$(cat /data/blob.sha)\" ]; \
             then echo SHA-OK; else echo SHA-BAD; fi",
        ])
        .output()
        .expect("exec verify snap");
    let snap_check = String::from_utf8_lossy(&o.stdout).trim_end().to_string();
    eprintln!("snap-layer: {snap_check:?}");
    drop(vm);

    eprintln!("=== commit -> read-only squashfs -> KVM-bootable image ===");
    let tc = Instant::now();
    let (commit, bootable) =
        builder::commit_kvm_bootable(&out.image, &commit_dir).expect("commit_kvm_bootable");
    eprintln!(
        "commit took {:?}; squashfs={} MiB sha={}",
        tc.elapsed(),
        commit.bytes / (1024 * 1024),
        &commit.sha256[..16]
    );

    eprintln!("=== boot FRESH from committed image, verify same FS ===");
    let vm2 = bootable.start(&VmConfig::new()).expect("start committed");
    std::thread::sleep(Duration::from_millis(4000));
    let o2 = vm2
        .exec_builder()
        .argv([
            "/bin/sh",
            "-c",
            "cat /data/marker; stat -c%s /data/blob; \
             if [ \"$(sha256sum /data/blob | cut -d' ' -f1)\" = \"$(cat /data/blob.sha)\" ]; \
             then echo SHA-OK; else echo SHA-BAD; fi",
        ])
        .output()
        .expect("exec verify committed");
    let committed_check = String::from_utf8_lossy(&o2.stdout).trim_end().to_string();
    eprintln!("committed: {committed_check:?}");
    drop(vm2);

    let committed_squashfs_bytes = commit.bytes;
    eprintln!("--- artifact sizes ---");
    eprintln!(
        "snapshot-layer image total (build_dest):      {} MiB",
        snap_bytes / (1024 * 1024)
    );
    eprintln!(
        "  of which restore.snap (full guest-RAM dump): {} MiB",
        restore_snap_bytes / (1024 * 1024)
    );
    eprintln!(
        "committed squashfs (read-only, shareable):     {} MiB",
        committed_squashfs_bytes / (1024 * 1024)
    );

    let pass = snap_check.contains("committed-density-ok")
        && snap_check.contains("SHA-OK")
        && committed_check.contains("committed-density-ok")
        && committed_check.contains("SHA-OK")
        && committed_check.contains(&(mib * 1024 * 1024).to_string());
    eprintln!(
        "=== COMMIT DENSITY LOOP: {} ===",
        if pass { "PASS" } else { "FAIL" }
    );
}

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