use rok_utils::data::numbers::{ceil, clamp, floor, format_number, lerp, round};

#[test]
fn numbers_format() {
    let result = format_number(1234567.89, 2, ',');
    assert_eq!(result, "1,234,567.89");

    let result = format_number(1234.5, 2, ',');
    assert_eq!(result, "1,234.50");
}

#[test]
fn numbers_rounding() {
    assert_eq!(round(3.14159, 2), 3.14);
    assert_eq!(round(3.14559, 2), 3.15);
    assert_eq!(round(-3.14159, 2), -3.14);

    assert_eq!(ceil(3.14159, 2), 3.15);
    assert_eq!(ceil(3.14000, 2), 3.14);

    assert_eq!(floor(3.14159, 2), 3.14);
    assert_eq!(floor(3.99999, 2), 3.99);
}

#[test]
fn numbers_clamp() {
    assert_eq!(clamp(5.0, 0.0, 10.0), 5.0);
    assert_eq!(clamp(-1.0, 0.0, 10.0), 0.0);
    assert_eq!(clamp(15.0, 0.0, 10.0), 10.0);
}

#[test]
fn numbers_lerp() {
    assert_eq!(lerp(0.0, 100.0, 0.0), 0.0);
    assert_eq!(lerp(0.0, 100.0, 0.5), 50.0);
    assert_eq!(lerp(0.0, 100.0, 1.0), 100.0);
}

#[cfg(feature = "dates")]
use rok_utils::{now, today, tomorrow, yesterday};

#[cfg(feature = "dates")]
#[test]
fn dates_now() {
    let n = now();
    assert!(n.timestamp() > 0);
}

#[cfg(feature = "dates")]
use chrono::Datelike;

#[cfg(feature = "dates")]
#[test]
fn dates_today_yesterday_tomorrow() {
    let t = today();
    let y = yesterday();
    let tm = tomorrow();

    assert_eq!(t.day() as i64 - y.day() as i64, 1);
    assert_eq!(tm.day() as i64 - t.day() as i64, 1);
}

#[cfg(feature = "dates")]
use rok_utils::add_days;

#[cfg(feature = "dates")]
#[test]
fn dates_math() {
    let t = today();
    let added = add_days(&t, 10);
    assert_eq!(added.day(), t.day() + 10);
}

#[cfg(feature = "ids")]
use rok_utils::{is_ulid, is_uuid, ulid, uuid_v4, uuid_v7};

#[cfg(feature = "ids")]
#[test]
fn ids_uuid_v4() {
    let u = uuid_v4();
    assert_eq!(u.len(), 36);
    assert!(is_uuid(&u));
    assert!(!is_uuid("not-a-uuid"));
}

#[cfg(feature = "ids")]
#[test]
fn ids_uuid_v7() {
    let u = uuid_v7();
    assert_eq!(u.len(), 36);
}

#[cfg(feature = "ids")]
#[test]
fn ids_ulid() {
    let u = ulid();
    assert_eq!(u.len(), 26);
    assert!(is_ulid(&u));
    assert!(!is_ulid("too-short"));
}

#[cfg(feature = "crypto")]
use rok_utils::{generate_token, hash_sha256, secure_compare, verify_sha256};

#[cfg(feature = "crypto")]
#[test]
fn crypto_hash() {
    let hash = hash_sha256("hello");
    assert_eq!(
        hash,
        "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
    );
}

#[cfg(feature = "crypto")]
#[test]
fn crypto_verify() {
    let hash = hash_sha256("hello");
    assert!(verify_sha256("hello", &hash));
    assert!(!verify_sha256("world", &hash));
}

#[cfg(feature = "crypto")]
#[test]
fn crypto_token() {
    let token = generate_token(32);
    assert!(!token.is_empty());
}

#[cfg(feature = "crypto")]
#[test]
fn crypto_secure_compare() {
    assert!(secure_compare("test", "test"));
    assert!(!secure_compare("test", "Test"));
}

#[cfg(feature = "random")]
use rok_utils::{password, random};

#[cfg(feature = "random")]
#[test]
fn random_string() {
    let s = random(32);
    assert_eq!(s.len(), 32);
}

#[cfg(feature = "random")]
#[test]
fn random_password() {
    let p = password(16, true);
    assert_eq!(p.len(), 16);
    assert!(p.chars().any(|c| c.is_alphabetic()));
    assert!(p.chars().any(|c| c.is_numeric()));
}
