use std::collections::HashSet;

use aok::{OK, Void};
use sfid::{EPOCH, SfId, parse};

static SF: SfId = SfId::new(EPOCH, 1);

fn test_snowflake(sf: &SfId) {
  let mut ids = HashSet::new();
  for _ in 0..10000 {
    let id = sf.get();
    assert!(ids.insert(id), "duplicate id: {id}");
  }
  println!("generated {} unique ids", ids.len());
}

fn test_parse(sf: &SfId) {
  let id = sf.get();
  let parsed = parse(id);
  println!(
    "id={id} ts={} pid={} seq={}",
    parsed.ts, parsed.pid, parsed.seq
  );
  assert!(parsed.ts > 0);
}

async fn test_concurrent(sf: &'static SfId) {
  let handles: Vec<_> = (0..4)
    .map(|_| {
      tokio::spawn(async move {
        let mut ids = Vec::with_capacity(1000);
        for _ in 0..1000 {
          ids.push(sf.get());
        }
        ids
      })
    })
    .collect();

  let mut all_ids = HashSet::new();
  for h in handles {
    let ids = h.await.unwrap();
    for id in ids {
      assert!(all_ids.insert(id), "duplicate id: {id}");
    }
  }
  println!("concurrent: {} unique ids", all_ids.len());
}

async fn test_new() -> Void {
  let sf = sfid::new("test").await?;
  let id = sf.get();
  let parsed = parse(id);
  println!(
    "new: id={id} ts={} pid={} seq={}",
    parsed.ts, parsed.pid, parsed.seq
  );
  assert!(parsed.ts > 0);

  OK
}

#[tokio::test(flavor = "multi_thread")]
async fn test() -> Void {
  log_init::init();
  xboot::init().await?;

  test_snowflake(&SF);
  test_parse(&SF);
  test_concurrent(&SF).await;
  test_new().await?;
  OK
}
