use rsa::{
    pkcs1v15::SigningKey,
    sha2::Sha256,
    signature::{RandomizedSigner, SignatureEncoding},
    Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey,
};

const RSA_CHUNK_SIZE: usize = 245;

#[must_use]
pub fn public_encrypt(public_key: &str, data: &[u8]) -> Option<Vec<u8>> {
    let public_key: RsaPublicKey =
        rsa::pkcs8::DecodePublicKey::from_public_key_pem(public_key).ok()?;
    let mut rng = rand::thread_rng();

    let mut result: Vec<u8> = Vec::new();
    for chunk in data.chunks(RSA_CHUNK_SIZE) {
        let encrypted_chunk = public_key.encrypt(&mut rng, Pkcs1v15Encrypt, chunk).ok()?;
        result.extend(encrypted_chunk);
    }

    Some(result)
}

#[must_use]
pub fn private_sign(private_key: &str, data: &[u8]) -> Option<Vec<u8>> {
    let private_key = rsa::pkcs1::DecodeRsaPrivateKey::from_pkcs1_pem(private_key).ok()?;
    let signing_key = SigningKey::<Sha256>::new(private_key);

    let mut rng = rand::thread_rng();
    Some(
        signing_key
            .sign_with_rng(&mut rng, data)
            .to_bytes()
            .to_vec(),
    )
}

#[must_use]
pub fn private_decrypt(private_key: &str, cipher: &[u8]) -> Option<Vec<u8>> {
    let private_key: RsaPrivateKey =
        rsa::pkcs1::DecodeRsaPrivateKey::from_pkcs1_pem(private_key).ok()?;
    private_key.decrypt(Pkcs1v15Encrypt, cipher).ok()
}
