use nom::combinator::map;
use nom::multi::length_data;
use nom::number::streaming::be_u16;
use nom::sequence::pair;
use nom::IResult;
use nom_derive::*;
use rusticata_macros::newtype_enum;
#[derive(Clone, Debug, PartialEq, Eq, Nom)]
pub struct HashAlgorithm(pub u8);
newtype_enum! {
impl display HashAlgorithm {
    None = 0,
    Md5 = 1,
    Sha1 = 2,
    Sha224 = 3,
    Sha256 = 4,
    Sha384 = 5,
    Sha512 = 6,
    Intrinsic = 8, }
}
#[derive(Clone, Debug, PartialEq, Eq, Nom)]
pub struct SignAlgorithm(pub u8);
newtype_enum! {
impl display SignAlgorithm {
    Anonymous = 0,
    Rsa = 1,
    Dsa = 2,
    Ecdsa = 3,
    Ed25519 = 7, Ed448 = 8, }
}
#[derive(Clone, PartialEq, Nom)]
pub struct SignatureAndHashAlgorithm {
    pub hash: HashAlgorithm,
    pub sign: SignAlgorithm,
}
#[derive(Debug, PartialEq, Eq, Nom)]
pub struct SignatureScheme(pub u16);
newtype_enum! {
impl display SignatureScheme {
    rsa_pkcs1_sha256 = 0x0401,
    rsa_pkcs1_sha384 = 0x0501,
    rsa_pkcs1_sha512 = 0x0601,
    ecdsa_secp256r1_sha256 = 0x0403,
    ecdsa_secp384r1_sha384 = 0x0503,
    ecdsa_secp521r1_sha512 = 0x0603,
    sm2sig_sm3 = 0x0708,
    rsa_pss_rsae_sha256 = 0x0804,
    rsa_pss_rsae_sha384 = 0x0805,
    rsa_pss_rsae_sha512 = 0x0806,
    ed25519 = 0x0807,
    ed448 = 0x0808,
    rsa_pss_pss_sha256 = 0x0809,
    rsa_pss_pss_sha384 = 0x080a,
    rsa_pss_pss_sha512 = 0x080b,
    ecdsa_brainpoolP256r1tls13_sha256 = 0x081a,
    ecdsa_brainpoolP384r1tls13_sha384 = 0x081b,
    ecdsa_brainpoolP512r1tls13_sha512 = 0x081c,
    rsa_pkcs1_sha1 = 0x0201,
    ecdsa_sha1 = 0x0203,
}
}
impl SignatureScheme {
    pub fn is_reserved(&self) -> bool {
        self.0 >= 0xfe00 && self.0 < 0xff00
    }
    pub fn hash_alg(&self) -> u8 {
        ((self.0 >> 8) & 0xff) as u8
    }
    pub fn sign_alg(&self) -> u8 {
        (self.0 & 0xff) as u8
    }
}
#[derive(Clone, PartialEq)]
pub struct DigitallySigned<'a> {
    pub alg: Option<SignatureAndHashAlgorithm>,
    pub data: &'a [u8],
}
pub fn parse_digitally_signed_old(i: &[u8]) -> IResult<&[u8], DigitallySigned> {
    map(length_data(be_u16), |data| DigitallySigned {
        alg: None,
        data,
    })(i)
}
pub fn parse_digitally_signed(i: &[u8]) -> IResult<&[u8], DigitallySigned> {
    let (i, hash) = HashAlgorithm::parse(i)?;
    let (i, sign) = SignAlgorithm::parse(i)?;
    let (i, data) = length_data(be_u16)(i)?;
    let signed = DigitallySigned {
        alg: Some(SignatureAndHashAlgorithm { hash, sign }),
        data,
    };
    Ok((i, signed))
}
pub fn parse_content_and_signature<F, T>(
    i: &[u8],
    fun: F,
    ext: bool,
) -> IResult<&[u8], (T, DigitallySigned)>
where
    F: Fn(&[u8]) -> IResult<&[u8], T>,
{
    if ext {
        pair(fun, parse_digitally_signed)(i)
    } else {
        pair(fun, parse_digitally_signed_old)(i)
    }
}