use dat::certificate::DatCertificate;
use dat::crypto::DatCryptoAlgorithm::{AES128GCMN, AES256GCMN};
use dat::error::DatError;
use dat::manager::DatManager;
use dat::signature::DatSignatureAlgorithm::{P256, P384, P521};
use dat::signature::DatSignatureKeyExportOption;
use dat::signature::DatSignatureKeyExportOption::PAIR;
use dat::util::now_unix_timestamp;
use rand::RngExt;

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

fn gen_certificate(dat_manager: &DatManager) -> Result<(), DatError> {
    let sign_alg_arr = [P256, P384, P521];
    let crypto_alg_arr = [AES128GCMN, AES256GCMN];
    let mut certificates: Vec<DatCertificate> = vec![];
    let now = now_unix_timestamp();
    let mut i = 0;
    sign_alg_arr.iter().for_each(|sign_alg| {
        crypto_alg_arr.iter().for_each(|crypto_alg| {
            (1..5).for_each(|_| {
                let cid = i;
                i += 1;
                certificates.push(DatCertificate::generate(cid, *sign_alg, *crypto_alg, now - 10, now + 600, 60).unwrap());
            });
        });
    });
    println!("Generated \n{}", certificates.iter().map(|x| x.export(PAIR).unwrap()).collect::<Vec<String>>().join("\n"));
    dat_manager.import_certificates(certificates, false)?;
    Ok(())
}

#[test]
fn test() {
    let manager = DatManager::new();
    let plain = rand_string();
    let secure = rand_string();

    // generate certificate
    gen_certificate(&manager).unwrap();

    // generate dats
    let certificates: Vec<DatCertificate> = manager.export_certificates();
    let dats: Vec<String> = certificates.iter().map(|key| {
        let dat: String = DatManager::_issue(&key, &plain, &secure).unwrap();
        dat
    }).collect::<Vec<String>>();

    // copy certificates
    let certificates = manager.export(DatSignatureKeyExportOption::PAIR);
    let manager2: DatManager = DatManager::new();
    manager2.import(&certificates, true).unwrap();

    // verify
    let tag = "dat.manager";
    for dat in dats {
        println!("{tag}.{}", dat);
        let payload = manager2.parse(dat.try_into().unwrap()).unwrap().to_string_payload().unwrap();
        println!("{tag}.{}", payload);
        assert_eq!(plain, payload.plain);
        assert_eq!(secure, payload.secure);
    }
}

//#[test]
#[allow(dead_code)]
fn temp() {
    let manager = DatManager::new();

    let certificates = "208.P256.0l0Zg3M6awe-EazlOPu2toOeCNLG0fJSg0jyFMxS0GA.AES128GCMN.80vsGYE1I0FuIg6IsGTcmg.1777223714.1777227314.1800
209.P256.0pPQ_IDM6cE_cnKoJCOpAvfwwPzdJCJkwFG2Kf43Oyg.AES128GCMN.leyMYpNByPzFRbNJ2-ThLw.1777224000.1777227600.1800
210.P256.WtoJ0Iewmaj8TciUUXNN1FQZ-w81LWw4LviMm13XWoQ.AES128GCMN.njKFMdgqgeaXxk7VOHyCBA.1777224600.1777228200.1800
211.P256.wIFMUNe2aeft8PZLbNGaY-tVDnjyQpcwc5c_P-t0ToQ.AES128GCMN.3x5V2iHBdRfcxFt2tkPL9w.1777225200.1777228800.1800
212.P256.GN_JVc6H1Br7JxGZdPeiFLOwZXv9aMNL1my83VOsMt8.AES128GCMN.U0-HEiRp_P7Pb0w1jCmtpw.1777225800.1777229400.1800
213.P256.neVA44aC5tondxG_kpRbqGPQfBvVvQbwDoe4H0mSGmQ.AES128GCMN.pXJsuId09_3MqtVZyr57NA.1777226400.1777230000.1800
214.P256.24ckfCvPnmjwEPIGWnYcfBeIm3smsD9ZOh4_hc7HjME.AES128GCMN.Qh5mEtpSN_3SQdQuC_Lz4Q.1777227000.1777230600.1800
215.P256.q4sNyIpb1HYguLwPFppKeIasODrYWpd8civBZYXATqo.AES128GCMN.IfUaX9a-WRR9Ex7IWWCFPQ.1777227600.1777231200.1800
216.P256.gr0o_sVihBuuB8H1XelCYlOl6rQ2tEXcb_2Ry13FSiY.AES128GCMN.5YmLe8ciqWdWaHE9DNqEgg.1777228200.1777231800.1800
217.P256.yLBPmlbBkAAz95vU8LRImpfDW4NiJUpTWH7iYkH6UmY.AES128GCMN.fLmUj4J3TA86ltBGKBPNAA.1777228800.1777232400.1800
218.P256.wJa-a4lD4g7d-GxqGtf4vnSeRRiIKDm80vph99Sv1w8.AES128GCMN.fSQWo5PMDBrWis8mM2xrNg.1777229400.1777233000.1800
219.P256.dSvJRLdmeRVHuzF5CkcoJ8gKZbZZLvk-okMrPUWnODw.AES128GCMN.0hvJxx8FKNr_OVEMt5PzRA.1777229615.1777233215.1800
220.P256.YvrE6Sn-1_tNQxVwT1qr2a9MfKLD_02X8TKD5xvfgf8.AES128GCMN.7imRXI1R-Jf730TqkgOm5Q.1777229631.1777233231.1800";

    manager.import(certificates, true).unwrap();

    let dat = manager.issue("hello", "world").unwrap();
    let payload = manager.parse(dat.try_into().unwrap()).unwrap().to_string_payload().unwrap();
    println!("{payload}");
    assert_eq!("hello", payload.plain);
    assert_eq!("world", payload.secure);
}