use dat::crypto_algorithm::CryptoAlgorithm::{AES128GCMN, AES256GCMN};
use dat::dat_payload::DatPayload;
use dat::dat_key::DatKey;
use dat::signature_algorithm::SignatureAlgorithm::{P256, P384, P521};
use dat::util::now_unix_timestamp;
use rand::RngExt;
use std::sync::Arc;
use std::time::Instant;
use tokio::task::JoinSet;
use dat::dat::Dat;

fn rand_string() -> String {
    let mut rng = rand::rng();
    (0..100).map(|_| { rng.sample(rand::distr::Alphanumeric) as char }).collect()
}

#[tokio::test(flavor = "multi_thread")]
async fn test() {
    if cfg!(debug_assertions) {
        println!("performance test is disabled in debug mode.");
        return;
    }

    let plain = Arc::new(rand_string());
    let secure = Arc::new(rand_string());

    println!("performance test (plain, secure)");
    println!("plain: {}", plain);
    println!("secure: {}", secure);

    for signature_algorithm in [P256, P384, P521] {
        for crypto_algorithm in [AES128GCMN, AES256GCMN] {
            let key = Arc::new(DatKey::<u64>::generate(0, signature_algorithm, crypto_algorithm, now_unix_timestamp() - 10, now_unix_timestamp() + 600, 60).unwrap());
            let mut futures: JoinSet<String> = JoinSet::new();
            let start = Instant::now();
            for _ in 0..10000 {
                let key = Arc::clone(&key);
                let plain = Arc::clone(&plain);
                let secure = Arc::clone(&secure);
                futures.spawn(async move {
                    key.to_dat(&*plain, &*secure).unwrap()
                });
            }
            let mut dat = String::new();
            while let Some(res) = futures.join_next().await {
                dat = res.unwrap();
            }
            let duration = start.elapsed(); // 경과 시간 계산
            println!("{}/{} to_dat * 10000 : {}ms", signature_algorithm, crypto_algorithm, duration.as_millis());
            //println!("last dat: {dat}");

            let dat = Arc::new(dat);
            let mut futures: JoinSet<DatPayload> = JoinSet::new();
            let start = Instant::now();
            for _ in 0..10000 {
                let key = Arc::clone(&key);
                let dat = Arc::clone(&dat);
                futures.spawn(async move {
                    let dat = (*dat).clone();
                    let dat: Dat<u64> = dat.try_into().unwrap();
                    key.to_payload(&dat).unwrap()
                });
            }
            while let Some(res) = futures.join_next().await {
                res.unwrap();
            }
            let duration = start.elapsed(); // 경과 시간 계산
            println!("{}/{} to_payload * 10000 : {}ms", signature_algorithm, crypto_algorithm, duration.as_millis());
            //println!("last payload: {}/{}", payload.0, payload.1);
        }
    }
}