use crate::HexUtil;
use base64::{prelude::BASE64_STANDARD, DecodeError, Engine};
use base64ct::LineEnding;
use hmac::{Hmac, Mac};
use rsa::{
    pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey},
    Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey,
};
use sha1::Sha1;
use sha2::{Digest, Sha256};
use soft_aes::aes::{aes_enc_ecb, aes_dec_ecb};

/// Encryption and decryption tools, which also include digest algorithms, etc.
pub struct SecureUtil;

impl SecureUtil {

    /// 进行aes加密
    ///
    /// 当前使用的是AES ECB Mode(简单模式)，
    /// 其他使用方式，见 https://crates.io/crates/soft-aes
    ///
    /// # 参数说明
    /// - data
    /// - key 要求16位 或 24位
    ///
    /// # 返回值
    /// - 返回的数据是bytes经过hex编码之后的字符串
    pub fn aes_encode(data: &str, key: &str) -> String {
        let plaintext = data.as_bytes();
        let key = key.as_bytes();
        let padding = Some("PKCS7");

        let encrypted = aes_enc_ecb(plaintext, key, padding).expect("Encryption failed");
        HexUtil::to_hex(&encrypted)
    }

    /// 进行aes解密
    ///
    /// # 参数说明
    /// - data 是一个hex编码的字符串
    /// - key 要求16位 或 24位
    pub fn aes_decode(data: &str, key: &str) -> String {
        let plaintext = HexUtil::to_bytes(data).unwrap();
        let key = key.as_bytes();
        let padding = Some("PKCS7");
        let decrypted = aes_dec_ecb(&plaintext, key, padding).expect("Decryption failed");
        String::from_utf8(decrypted).unwrap()
    }

    /// 生成RSA随机密钥对
    ///
    /// 该函数使用系统随机数生成器创建一个2048位的RSA密钥对。
    ///
    /// # 返回值
    /// * `RsaPublicKey` - RSA公钥
    /// * `RsaPrivateKey` - RSA私钥
    ///
    /// # Panics
    /// 当密钥生成失败时会panic
    pub fn rsa_random_key() -> (RsaPublicKey, RsaPrivateKey) {
        let mut rng = rand::thread_rng(); // rand@0.8
        let bits = 2048;
        // 生成RSA私钥
        let priv_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
        // 从私钥导出公钥
        let pub_key = RsaPublicKey::from(&priv_key);
        (pub_key, priv_key)
    }

    /// 使用RSA公钥对字节数据进行加密
    ///
    /// 该函数使用PKCS#1 v1.5填充方案对输入的字节数据进行RSA加密操作。
    /// 加密过程中会使用随机数生成器来确保加密的安全性。
    ///
    /// # 参数
    /// * `pub_key` - RSA公钥引用，用于执行加密操作
    /// * `bytes` - 需要加密的原始字节数据
    ///
    /// # 返回值
    /// 返回加密后的字节数据向量
    ///
    /// # Panics
    /// 当加密操作失败时会panic，例如输入数据过长等情况
    pub fn rsa_encode(pub_key: &RsaPublicKey, bytes: &[u8]) -> Vec<u8> {
        let mut rng = rand::thread_rng(); // rand@0.8
        let enc_data = pub_key
            .encrypt(&mut rng, Pkcs1v15Encrypt, bytes)
            .expect("failed to encrypt");
        enc_data
    }

    /// 使用RSA私钥解密数据
    ///
    /// # 参数
    /// * `priv_key` - RSA私钥引用，用于解密操作
    /// * `enc_data` - 待解密的加密数据字节切片
    ///
    /// # 返回值
    /// 返回解密后的原始数据字节向量
    ///
    /// # Panics
    /// 当解密操作失败时会panic
    pub fn rsa_decode(priv_key: &RsaPrivateKey, enc_data: &[u8]) -> Vec<u8> {
        // 使用PKCS#1 v1.5填充方案进行RSA解密
        let dec_data = priv_key
            .decrypt(Pkcs1v15Encrypt, &enc_data)
            .expect("failed to decrypt");
        dec_data
    }

    /// 将RSA私钥转换为PKCS#8格式的PEM字符串
    ///
    /// 该函数接收一个RSA私钥对象，将其序列化为PKCS#8格式的PEM编码字符串。
    /// PKCS#8是一种标准的私钥存储格式，使用PEM编码便于文本传输和存储。
    ///
    /// # 参数
    /// * `priv_key` - 要转换的RSA私钥引用
    ///
    /// # 返回值
    /// 返回PKCS#8格式的PEM编码字符串
    ///
    /// # Panics
    /// 当私钥转换失败时会panic，因为使用了unwrap()
    pub fn rsa_private_key_to_pkcs8(priv_key: &RsaPrivateKey) -> String {
        let x = priv_key.to_pkcs8_pem(LineEnding::LF).unwrap();
        x.to_string()
    }

    /// 将RSA公钥转换为PKCS#8格式的PEM字符串
    ///
    /// 该函数接收一个RSA公钥对象，将其序列化为PEM格式的字符串，
    /// 使用LF作为换行符
    ///
    /// # 参数
    /// * `pub_key` - 要转换的RSA公钥引用
    ///
    /// # 返回值
    /// 返回PEM格式的PKCS#8公钥字符串
    ///
    /// # Panics
    /// 当公钥转换失败时会panic（通过unwrap调用）
    pub fn rsa_public_key_to_pkcs8(pub_key: &RsaPublicKey) -> String {
        let x = pub_key.to_public_key_pem(LineEnding::LF).unwrap();
        x
    }

    /// 从PKCS#8格式的PEM字符串中解析RSA私钥
    ///
    /// 该函数接收一个PKCS#8格式的PEM编码字符串，将其解析为RsaPrivateKey对象。
    ///
    /// # 参数
    /// * `pkcs8_string` - 包含PKCS#8格式RSA私钥的PEM编码字符串
    ///
    /// # 返回值
    /// 返回解析得到的RsaPrivateKey对象
    ///
    /// # Panics
    /// 当PEM字符串格式不正确或无法解析时，函数会panic
    pub fn rsa_private_key_from_pkcs8(pkcs8_string: &str) -> RsaPrivateKey {
        // 从PKCS#8 PEM字符串解析RSA私钥
        let res = RsaPrivateKey::from_pkcs8_pem(pkcs8_string).unwrap();
        res
    }
    /// 从PKCS8格式的字符串创建RSA公钥
    ///
    /// 该函数接收一个PKCS8格式的PEM编码字符串，将其解析为RSA公钥对象。
    ///
    /// # 参数
    /// * `pkcs8_string` - PKCS8格式的PEM编码字符串
    ///
    /// # 返回值
    /// * `RsaPublicKey` - 解析得到的RSA公钥对象
    ///
    /// # 注意
    /// 该函数使用unwrap()处理结果，如果解析失败会panic
    pub fn rsa_public_key_from_pkcs8(pkcs8_string: &str) -> RsaPublicKey {
        let res = RsaPublicKey::from_public_key_pem(pkcs8_string).unwrap();
        res
    }

    /// 计算字节数组的SHA256哈希值并返回十六进制字符串
    ///
    /// 固定生成256 位（32 字节） 的哈希值，以 64 位十六进制字符串形式展示
    ///
    /// # 参数
    /// * `bytes` - 需要计算哈希值的字节数组切片
    ///
    /// # 返回值
    /// 返回SHA256哈希值的十六进制字符串表示
    pub fn sha256_string(bytes: &[u8]) -> String {
        // 计算SHA256哈希值
        let result = Sha256::digest(bytes);
        let result = &result[..];
        // 将哈希值转换为十六进制字符串
        HexUtil::to_hex(result)
    }

    pub fn md5_string(bytes: &[u8]) -> String {
        // 计算输入数据的MD5哈希值
        let data_md5 = md5::compute(bytes);
        // 将MD5哈希值格式化为十六进制字符串
        let md5_string = format!("{:x}", data_md5);
        md5_string
    }

    /// 对字节数组进行Base64编码
    ///
    /// # 参数
    /// * `bytes` - 需要编码的字节数组切片
    ///
    /// # 返回值
    /// 返回编码后的Base64字符串
    pub fn base64_encode(bytes: &[u8]) -> String {
        BASE64_STANDARD.encode(bytes)
    }

    /// 对Base64编码的字符串进行解码
    ///
    /// # 参数
    /// * `base64_str` - 需要解码的Base64编码字符串
    ///
    /// # 返回值
    /// * `Ok(Vec<u8>)` - 解码成功，返回解码后的字节数据
    /// * `Err(DecodeError)` - 解码失败，返回错误信息
    ///
    /// # 示例
    /// ```
    /// let decoded = base64_decode("SGVsbG8=").unwrap();
    /// assert_eq!(decoded, b"Hello");
    /// ```
    pub fn base64_decode(base64_str: &str) -> Result<Vec<u8>, DecodeError> {
        BASE64_STANDARD.decode(base64_str)
    }

    /// 使用HMAC-SHA1算法对数据进行签名
    ///
    /// 该函数接收待签名的数据和密钥，使用HMAC-SHA1算法生成数字签名。
    ///
    /// # 参数
    /// * `data` - 待签名的字节数据切片
    /// * `key` - 用于签名的密钥字符串
    ///
    /// # 返回值
    /// 返回HMAC-SHA1签名结果的字节向量
    ///
    /// # Panics
    /// 当密钥长度无效时会panic，但在实际中HMAC可以接受任意长度的密钥
    pub fn hmac_sha1(data: &[u8], key: &str) -> Vec<u8> {
        let key = key.as_bytes();
        // 创建HMAC-SHA1实例并初始化
        let mut hmac = Hmac::<Sha1>::new_from_slice(key).expect("HMAC can take key of any size");
        // 更新HMAC状态，处理输入数据
        hmac.update(data);
        // 完成HMAC计算并获取结果
        let result = hmac.finalize();
        let hmac_bytes = result.into_bytes();
        hmac_bytes.to_vec()
    }

    /// 将字节数组转换为MD5哈希字符串
    ///
    /// 该函数接收一个字节切片，计算其MD5哈希值，并将结果格式化为十六进制字符串。
    ///
    /// # 参数
    /// * `bytes` - 需要计算MD5哈希的字节数据切片
    ///
    /// # 返回值
    /// 返回表示MD5哈希值的十六进制字符串
    ///
    /// # 示例
    /// ```
    /// let data = b"hello world";
    /// let md5_str = to_md5_str(data);
    /// assert_eq!(md5_str, "5eb63bbbe01eeed093cb22bb8f5acdc3");
    /// ```
    #[deprecated(note = "This function is deprecated, please use md5_string instead")]
    pub fn to_md5_str(bytes: &[u8]) -> String {
        Self::md5_string(bytes)
    }

    /// 计算字节数组的MD5哈希值
    ///
    /// # 参数
    /// * `bytes` - 需要计算MD5哈希值的字节数组切片
    ///
    /// # 返回值
    /// 返回计算得到的MD5哈希值，以字节数组形式表示
    ///
    /// # 示例
    /// ```
    /// let data = b"hello world";
    /// let hash = to_md5(data);
    /// ```
    pub fn to_md5(bytes: &[u8]) -> Vec<u8> {
        // 使用md5库计算输入数据的哈希值并转换为Vec<u8>
        let data_md5 = md5::compute(bytes).to_vec();
        data_md5
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_aes() {
        let origin = "Hello, this is TheoryDance!";
        let key = "hello123hbjnk8h1";
        let encode_string = SecureUtil::aes_encode(origin, key);
        println!("1=>{}", encode_string);
        let decode_string = SecureUtil::aes_decode(&encode_string, key);
        println!("2=>{}", decode_string);
    }

    #[test]
    fn test_base64() {
        let bytes = "hello, rust!".as_bytes();
        let base64_str = SecureUtil::base64_encode(bytes);
        println!("{}", base64_str);
    }

    #[test]
    fn test_sha256() {
        let sha256_string = SecureUtil::sha256_string(b"hello world");
        println!("{}", sha256_string);
        assert_eq!(
            sha256_string,
            "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
        );
    }

    #[test]
    fn test_rsa() {
        let (pub_key, priv_key) = SecureUtil::rsa_random_key();
        // let data = "hello world";
        // let enc_data = SecureUtil::rsa_encode(&pub_key, data.as_bytes());
        // let dec_data = SecureUtil::rsa_decode(&priv_key, &enc_data);
        // assert_eq!(data, std::str::from_utf8(&dec_data).unwrap());
        // println!("{:?}", pub_key);
        // let x = priv_key.to_pkcs8_pem(LineEnding::LF).unwrap();
        // let y = (*x).clone();
        // let x = x.to_string();
        // println!("{}", y);

        let pub_pkcs8_string = SecureUtil::rsa_public_key_to_pkcs8(&pub_key);
        let priv_pkcs8_string = SecureUtil::rsa_private_key_to_pkcs8(&priv_key);

        println!("pub_pkcs8_string => {}", pub_pkcs8_string);
        println!("priv_pkcs8_string => {}", priv_pkcs8_string);

        let pub_key = SecureUtil::rsa_public_key_from_pkcs8(&pub_pkcs8_string);
        let priv_key = SecureUtil::rsa_private_key_from_pkcs8(&priv_pkcs8_string);

        let data = "hello world";
        let enc_data = SecureUtil::rsa_encode(&pub_key, data.as_bytes());
        let dec_data = SecureUtil::rsa_decode(&priv_key, &enc_data);
        println!("解密后{}", std::str::from_utf8(&dec_data).unwrap())
    }

    #[test]
    fn test_rsa2() {
        // https://www.metools.info/code/c80.html 生成RSA密钥对
        let pub_pkcs8_string = r#"-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6HvM5v45WMgCVCM7gLyU
q8Xi0fqwvfge7JU9C6niP+liQHyMALr9n+IQm76v/CnvfAYYnDJ1VYhLpGkPKJ2Q
56InmEOSAcx9vfgGQcPkkTSqpH/vDHEgPysFsBAGVBvXfBxa9FBF8afrAmdqM3DO
ygnWWCaSux0js2hkQB0+wUk3Lkw9yxcT+cK9D7aNaB3vVjxRVvGOuFVMuTFzLjis
/1INfltSSvnCB4QPxA/h9YUrZ26itw7yQgGIiUbNydLx3X+qvWCGVOnYwX9z6wsF
4Ch3VwlYF+H/y0zyjIuCpdJDy80D36lErcwmRpJhMciT4lXnLMTyZvlN0UFl492L
1wIDAQAB
-----END PUBLIC KEY-----"#;
        let priv_pkcs8_string = r#"-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDoe8zm/jlYyAJU
IzuAvJSrxeLR+rC9+B7slT0LqeI/6WJAfIwAuv2f4hCbvq/8Ke98BhicMnVViEuk
aQ8onZDnoieYQ5IBzH29+AZBw+SRNKqkf+8McSA/KwWwEAZUG9d8HFr0UEXxp+sC
Z2ozcM7KCdZYJpK7HSOzaGRAHT7BSTcuTD3LFxP5wr0Pto1oHe9WPFFW8Y64VUy5
MXMuOKz/Ug1+W1JK+cIHhA/ED+H1hStnbqK3DvJCAYiJRs3J0vHdf6q9YIZU6djB
f3PrCwXgKHdXCVgX4f/LTPKMi4Kl0kPLzQPfqUStzCZGkmExyJPiVecsxPJm+U3R
QWXj3YvXAgMBAAECggEATgrBDgnpVlRN89Cf+OdVQRR8v+BX1G2mc+TlSTUOLkY6
JUup89TRrwpEaQPqL8wkCI5DVKvbl4rZWaeq3weFzTwx7ntAWDo9O7g24XzRDa2Q
WwhXRuXy3UGj9yZp+XIfNBqQrdMEp8qmqXftvrbvtAL5YT4Ro550jZVNkfg/SMKX
VptR+ZGpjSWsQfLM+Q8i9GEo3FV1dpT41Uea96cfX2siaaNNhCUM3MYgVDRjp7gj
N9qxHOil3ZmvJU2yRLBlwgtLO+5fQzGET/yOeoXJ9iCeyAz5MNweljdra4wNtriV
9ECYR/d7R3Bz2DtaJ5ALyD80AeJ+1TTrLxa4exkHgQKBgQD7UXolf0J5qFMEn7yw
0F7LNANX/Fx6T/ayf7MJEegHK0UYDc9wjyIQDcIdgauvqImseq7R5sQQbnAHdsZW
f6bzb+1HjoUZr2c43QY4sBRDW7wfibtlgtaiMpIophlBwbvdcJRW65s7Ox8Czcl/
JNqMdjXjHLSiEFND6v8Of68LFQKBgQDs0IByiZm7qJQaR8WOoXku5C0XLA5zCLyh
jXTqla5m0qAFZU8abrvBl/o0+nhmGsMkQR0ssvLJLX/a0t1IWBq+WmIDB3YC4IVU
eKoHY7AlDhMa0dJ+nbuvrPQdFsRAfH9CRhtMmQPCVsx41AXsQa/OKwUQJuNvhwMg
AioMthWGOwKBgG6tvTtSRjZJuPXqWzELMxQOfgJ7s0ZyfNSzhGdUKXkuxykGu/p4
LqofRQO1naSodqktBlyOYn5SBKhk2Igzg5TmD/tZeqiLJMxYGmtQsDvR5JGHGK5l
5pxb5R5dt/XLmi61a76z2BNHwCp98mU6F72QOb8hXzOYOPNKRLVf6fjZAoGBAJD2
2YpDvT3o5jBoOwEiy4Hu38NNjtLQSFhEtYtccVQ0HwzuhUvS+VB67gk8QjOOsmIh
EfDo4kJQffHAHwFIHabkwRbFnHIKatPYwYygc5VbVkqWotorSFcz8oNUCnLHQ0eY
juGG0YxHggd9EtsbIrl8EC9g/tyoszsG2CLL28U9AoGAbZsQM7989SiKtLJ652uw
6kaRWItbBdVKPr5galsBhbe/eEEE6ePbJTeLroQ31u/jGZJNSyUjwfBq9k1OBfpL
s7+EjYm9Yg5hcep499C2eRyqoX+2j8am2CYYy3rDPj8lYt+u/99oUyAyGYVKAByb
j27x2gyifpYUwtDqYU5DwDU=
-----END PRIVATE KEY-----"#;

        println!("pub_pkcs8_string => {}", pub_pkcs8_string);
        println!("priv_pkcs8_string => {}", priv_pkcs8_string);

        let pub_key = SecureUtil::rsa_public_key_from_pkcs8(&pub_pkcs8_string);
        let priv_key = SecureUtil::rsa_private_key_from_pkcs8(&priv_pkcs8_string);

        let data = "hello world";
        let enc_data = SecureUtil::rsa_encode(&pub_key, data.as_bytes());
        let dec_data = SecureUtil::rsa_decode(&priv_key, &enc_data);
        println!("解密后{}", std::str::from_utf8(&dec_data).unwrap())
    }
}
