use clap::Parser;
use rand::{Rng, SeedableRng};
use ringdb::{QueryResult, RingDb, RingDbConfig, RingQuery};

/// ringdb CLI — generate a random dataset and run a ring query.
///
/// Example:
///
///   cargo run --example cli -- --n 100000 --dims 64 --d 5.0 --lambda 0.2
#[derive(Parser)]
#[command(name = "ringdb-cli", about = "ringdb demo: random dataset ring query")]
struct Cli {
    /// Number of random vectors to generate.
    #[arg(short, long, default_value_t = 10_000)]
    n: usize,

    /// Number of dimensions per vector.
    #[arg(long, default_value_t = 128)]
    dims: usize,

    /// Target distance (centre of ring).
    #[arg(short = 'd', long, default_value_t = 5.0)]
    d: f32,

    /// Half-width of the ring (λ).
    #[arg(short = 'l', long, default_value_t = 0.5)]
    lambda: f32,

    /// Random seed for reproducibility.
    #[arg(long, default_value_t = 42)]
    seed: u64,
}

fn main() {
    let cli = Cli::parse();

    let config = RingDbConfig::new(cli.dims);

    println!("ringdb demo");
    println!("  dataset : {} vectors × {} dims", cli.n, cli.dims);
    println!("  ring    : d={}, λ={}", cli.d, cli.lambda);
    println!();

    print!("Building database … ");
    let build_start = std::time::Instant::now();
    let mut db = RingDb::new(config).expect("failed to create RingDb");

    let mut rng = rand::rngs::SmallRng::seed_from_u64(cli.seed);
    let mut buf = vec![0.0f32; cli.dims];

    for x in buf.iter_mut() {
        *x = rng.gen_range(-1.0f32..1.0);
    }
    let query_vec = buf.clone();
    db.add_vector(&buf, ()).expect("failed to add vector");

    for _ in 1..cli.n {
        for x in buf.iter_mut() {
            *x = rng.gen_range(-1.0f32..1.0);
        }
        db.add_vector(&buf, ()).expect("failed to add vector");
    }

    let db = db.build().expect("failed to build");

    let build_elapsed = build_start.elapsed();
    println!("done in {:.2?}", build_elapsed);
    println!("  backend : {}", db.backend_name());
    println!();

    let rq = RingQuery {
        query: &query_vec,
        d: cli.d,
        lambda: cli.lambda,
    };

    print!("Running ring query … ");
    let QueryResult {
        ids,
        backend_used,
        elapsed,
    } = db.query(&rq).expect("query failed");

    println!("done");
    println!();
    println!("Results:");
    println!("  backend      : {backend_used}");
    println!("  hits         : {}", ids.len());
    println!("  query time   : {elapsed:.2?}");

    if ids.len() <= 20 {
        println!("  hit IDs      : {ids:?}");
    } else {
        println!("  hit IDs      : [{}, {}, … {} total]", ids[0], ids[1], ids.len());
    }
}
