use std::path::PathBuf;
use std::time::Duration;

use supermachine::{Image, PullPolicy};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mount_host = std::env::args()
        .nth(1)
        .map(PathBuf::from)
        .expect("usage: runsc_warmup_smoke <host-mount-dir>");
    std::fs::create_dir_all(&mount_host)?;

    let image = Image::builder("alpine:3.20")
        .with_name(format!(
            "runsc-warmup-smoke-{}-{}",
            std::process::id(),
            unique_suffix()
        ))
        .with_pull_policy(PullPolicy::Missing)
        .with_mount(mount_host, "host", "/host")
        .with_warmup(|vm| {
            let out = vm
                .exec_builder()
                .argv([
                    "sh",
                    "-lc",
                    "echo warmed >/host/warm.txt; (while true; do date +%s >/tmp/tick; sleep 1; done) >/dev/null 2>&1 </dev/null & echo $! >/tmp/warm.pid",
                ])
                .timeout(Duration::from_secs(20))
                .output()?;
            if out.success() {
                Ok(())
            } else {
                Err(supermachine::Error::Vm {
                    msg: format!(
                    "warmup failed: status={:?} stdout={} stderr={}",
                    out.status.code(),
                    String::from_utf8_lossy(&out.stdout),
                    String::from_utf8_lossy(&out.stderr)
                ),
                    source: None,
                })
            }
        })
        .build()?;

    let pool = image.pool().max(1).build()?;
    let vm = pool.acquire()?;
    let out = vm
        .exec_builder()
        .argv([
            "sh",
            "-lc",
            "cat /host/warm.txt; test -s /tmp/tick; kill -0 $(cat /tmp/warm.pid); echo restored",
        ])
        .timeout(Duration::from_secs(20))
        .output()?;
    print!("{}", String::from_utf8_lossy(&out.stdout));
    eprint!("{}", String::from_utf8_lossy(&out.stderr));
    pool.shutdown();
    if out.success() {
        Ok(())
    } else {
        std::process::exit(out.status.code().unwrap_or(1));
    }
}

fn unique_suffix() -> u128 {
    std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .map(|d| d.as_nanos())
        .unwrap_or(0)
}
