use {
    crate::error::Error, num_bigint_dig::traits::ModInverse, rsa::PublicKeyParts,
    simple_asn1::ASN1Block,
};

/// Encode an RSA private key with PKCS#1
pub fn private_key(key: &rsa::RSAPrivateKey) -> Result<Vec<u8>, Error> {
    let mut data = Vec::new();

    data.push(ASN1Block::Integer(0, simple_asn1::BigInt::default()));
    data.push(ASN1Block::Integer(0, crate::to_bigint(key.n())));
    data.push(ASN1Block::Integer(0, crate::to_bigint(key.e())));
    data.push(ASN1Block::Integer(0, crate::to_bigint(key.d())));

    let primes = key.primes();
    let prime_1 = &primes[0];
    let prime_2 = &primes[1];

    data.push(ASN1Block::Integer(0, crate::to_bigint(prime_1)));
    data.push(ASN1Block::Integer(0, crate::to_bigint(prime_2)));
    data.push(ASN1Block::Integer(
        0,
        crate::to_bigint(&(key.d() % (prime_1 - 1_u8))),
    ));
    data.push(ASN1Block::Integer(
        0,
        crate::to_bigint(&(key.d() % (prime_2 - 1_u8))),
    ));

    let coefficient = match prime_2.to_owned().mod_inverse(prime_1) {
        Some(val) => val,
        None => return Err(Error::ModInverse),
    }
    .to_signed_bytes_le();

    data.push(ASN1Block::Integer(
        0,
        simple_asn1::BigInt::from_signed_bytes_le(coefficient.as_slice()),
    ));

    simple_asn1::to_der(&ASN1Block::Sequence(0, data)).map_err(Into::into)
}

/// Encode an RSA public key with PKCS#1
pub fn public_key(key: &rsa::RSAPublicKey) -> Result<Vec<u8>, Error> {
    let mut data = Vec::new();

    data.push(ASN1Block::Integer(0, crate::to_bigint(key.n())));
    data.push(ASN1Block::Integer(0, crate::to_bigint(key.e())));

    simple_asn1::to_der(&ASN1Block::Sequence(0, data)).map_err(Into::into)
}
