// CLI integration tests that invoke the compiled binary as a subprocess.

use std::process::Command;
use std::time::{SystemTime, UNIX_EPOCH};

fn unique_test_dir(prefix: &str) -> std::path::PathBuf {
    let nanos = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .expect("system time should be after unix epoch")
        .as_nanos();
    std::env::temp_dir().join(format!("{prefix}-{}-{nanos}", std::process::id()))
}

fn run_basic_agent(args: &[&str]) -> std::process::Output {
    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| ".".into());
    Command::new(env!("CARGO"))
        .arg("run")
        .arg("--quiet")
        .arg("-p")
        .arg("basic-agent")
        .arg("--")
        .args(args)
        .current_dir(manifest_dir)
        .output()
        .expect("failed to execute cargo run for basic-agent")
}

#[test]
fn run_script_file_prints_output_to_stdout() {
    let tmp = unique_test_dir("sandlet-cli-test");
    let script_path = tmp.join("hello.roto");
    std::fs::create_dir_all(&tmp).unwrap();
    std::fs::write(
        &script_path,
        r#"fn main() -> String { strings_uppercase("sandlet") }"#,
    )
    .unwrap();

    let script_path = script_path.to_string_lossy().to_string();
    let output = run_basic_agent(&["run", "--script", &script_path]);

    let stdout = String::from_utf8_lossy(&output.stdout);
    assert!(
        output.status.success(),
        "expected success, got stderr: {}",
        String::from_utf8_lossy(&output.stderr)
    );
    assert!(
        stdout.contains("SANDLET"),
        "expected SANDLET in stdout, got: {stdout}"
    );
}

#[test]
fn run_invalid_script_path_produces_failure() {
    let output = run_basic_agent(&["run", "--script", "/nonexistent/path/script.roto"]);

    assert!(
        !output.status.success(),
        "expected failure for missing script path"
    );
    let stderr = String::from_utf8_lossy(&output.stderr);
    assert!(
        stderr.contains("load-script-failed")
            || stderr.contains("No such file")
            || stderr.contains("entrypoint")
            || stderr.contains("Roto")
            || stderr.contains("error"),
        "expected an error message in stderr, got: {stderr}"
    );
}

#[test]
fn run_invalid_script_source_produces_failure() {
    let tmp = unique_test_dir("sandlet-cli-test-invalid");
    let script_path = tmp.join("bad.roto");
    std::fs::create_dir_all(&tmp).unwrap();
    std::fs::write(&script_path, "fn broken { ").unwrap();

    let script_path = script_path.to_string_lossy().to_string();
    let output = run_basic_agent(&["run", "--script", &script_path]);

    assert!(
        !output.status.success(),
        "expected failure for invalid script source"
    );
    let stderr = String::from_utf8_lossy(&output.stderr);
    assert!(
        stderr.contains("roto-compile-error")
            || stderr.contains("Roto compilation failed")
            || stderr.contains("error"),
        "expected compile error in stderr, got: {stderr}"
    );
}
