use crate::error::DatError;
use crate::signature::DatSignature::HmacShaMfs;
use crate::signature::{DatSignature, DatSignatureAlgorithm};
use aws_lc_rs::hmac;
use aws_lc_rs::hmac::{Key, HMAC_SHA256, HMAC_SHA384, HMAC_SHA512};
use DatSignatureAlgorithm::*;

pub(crate) fn from_or_new_hmac(new: bool, algorithm: DatSignatureAlgorithm, key_b: &[u8]) -> Result<DatSignature, DatError> {
    let (alg, size) = match algorithm {
        HmacSha256Mfs => (&HMAC_SHA256, 32),
        HmacSha384Mfs => (&HMAC_SHA384, 48),
        HmacSha512Mfs => (&HMAC_SHA512, 64),
        _ => return Err(DatError::UnknownSignatureAlgorithm),
    };


    let (key, key_b) = if new {
        let mut key_b = vec![0u8; size];
        aws_lc_rs::rand::fill(&mut key_b)
            .map_err(|_| DatError::GenerateSigningKeyError)?;
        let key = Key::new(*alg, &key_b);
        (key, key_b)
    } else if key_b.len() == size {
        let key = Key::new(*alg, &key_b);
        (key, Vec::from(key_b))
    } else {
        return Err(DatError::InvalidSignatureKey)
    };

    Ok(HmacShaMfs(algorithm, key, key_b))
}

pub(crate) fn sign_hmac(key: &Key, data: &[u8]) -> Result<Box<[u8]>, DatError> {
    Ok(Box::from(hmac::sign(key, data).as_ref()))
}

pub(crate) fn verify_hmac(key: &Key, body: &[u8], sign: &[u8]) -> Result<(), DatError> {
    hmac::verify(key, body, sign)
        .map_err(|_| DatError::InvalidDat)
}
