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

#[test]
fn module_e_fst_cli_smoke() {
    let binary = env!("CARGO_BIN_EXE_tracer-bullet");
    let index_path = unique_path("module-e-fst").with_extension("fst");

    let output = Command::new(binary)
        .args([
            "module-e-fst",
            "--keys",
            "20000",
            "--lookups",
            "2000",
            "--list-queries",
            "2000",
            "--index-path",
            index_path.to_str().expect("path should be utf-8"),
            "--json",
        ])
        .output()
        .expect("failed to execute module-e-fst command");

    assert!(
        output.status.success(),
        "module-e-fst command failed: status={:?} stderr={} stdout={}",
        output.status,
        String::from_utf8_lossy(&output.stderr),
        String::from_utf8_lossy(&output.stdout)
    );

    let stdout = String::from_utf8_lossy(&output.stdout);
    assert!(stdout.contains("\"module\":\"E_FST\""));
    assert!(stdout.contains("\"keys\":20000"));

    let _ = std::fs::remove_file(index_path);
}

#[test]
fn module_e_trie_cli_smoke() {
    let binary = env!("CARGO_BIN_EXE_tracer-bullet");

    let output = Command::new(binary)
        .args([
            "module-e-trie",
            "--keys",
            "20000",
            "--lookups",
            "2000",
            "--list-queries",
            "2000",
            "--json",
        ])
        .output()
        .expect("failed to execute module-e-trie command");

    assert!(
        output.status.success(),
        "module-e-trie command failed: status={:?} stderr={} stdout={}",
        output.status,
        String::from_utf8_lossy(&output.stderr),
        String::from_utf8_lossy(&output.stdout)
    );

    let stdout = String::from_utf8_lossy(&output.stdout);
    assert!(stdout.contains("\"module\":\"E_TRIE\""));
    assert!(stdout.contains("\"keys\":20000"));
}

#[test]
fn module_e_compare_cli_smoke() {
    let binary = env!("CARGO_BIN_EXE_tracer-bullet");
    let index_path = unique_path("module-e-compare").with_extension("fst");

    let output = Command::new(binary)
        .args([
            "module-e-compare",
            "--keys",
            "15000",
            "--lookups",
            "1500",
            "--list-queries",
            "1500",
            "--index-path",
            index_path.to_str().expect("path should be utf-8"),
            "--json",
        ])
        .output()
        .expect("failed to execute module-e-compare command");

    assert!(
        output.status.success(),
        "module-e-compare command failed: status={:?} stderr={} stdout={}",
        output.status,
        String::from_utf8_lossy(&output.stderr),
        String::from_utf8_lossy(&output.stdout)
    );

    let stdout = String::from_utf8_lossy(&output.stdout);
    assert!(stdout.contains("\"module\":\"E_COMPARE\""));
    assert!(stdout.contains("\"recommendation\":"));

    let _ = std::fs::remove_file(index_path);
}

#[test]
#[ignore = "heavy 50M key compare benchmark"]
fn module_e_compare_full_scale() {
    let binary = env!("CARGO_BIN_EXE_tracer-bullet");
    let index_path = unique_path("module-e-full").with_extension("fst");

    let status = Command::new(binary)
        .args([
            "module-e-compare",
            "--keys",
            "50000000",
            "--lookups",
            "100000",
            "--list-queries",
            "100000",
            "--index-path",
            index_path.to_str().expect("path should be utf-8"),
            "--json",
        ])
        .status()
        .expect("failed to execute full-scale module-e-compare command");

    assert!(status.success(), "full-scale module-e compare failed");

    let _ = std::fs::remove_file(index_path);
}

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