use base64::prelude::*;
use sha3::{
    Keccak224, Keccak256, Keccak256Full, Keccak384, Keccak512, Sha3_224, Sha3_256, Sha3_384,
    Sha3_512,
};

use super::DigestCreate;

fn create<D: sha3::Digest + sha3::digest::FixedOutputReset>(
    digest: &mut D,
    input: &[u8],
) -> String {
    sha3::Digest::update(digest, input);
    BASE64_STANDARD.encode(&digest.finalize_reset())
}

impl DigestCreate for Sha3_224 {
    const NAME: &'static str = "SHA3-224";

    fn compute(&mut self, input: &[u8]) -> String {
        create(self, input)
    }
}

impl DigestCreate for Sha3_256 {
    const NAME: &'static str = "SHA3-256";

    fn compute(&mut self, input: &[u8]) -> String {
        create(self, input)
    }
}

impl DigestCreate for Sha3_384 {
    const NAME: &'static str = "SHA3-384";

    fn compute(&mut self, input: &[u8]) -> String {
        create(self, input)
    }
}

impl DigestCreate for Sha3_512 {
    const NAME: &'static str = "SHA3-512";

    fn compute(&mut self, input: &[u8]) -> String {
        create(self, input)
    }
}

impl DigestCreate for Keccak224 {
    const NAME: &'static str = "keccak-224";

    fn compute(&mut self, input: &[u8]) -> String {
        create(self, input)
    }
}

impl DigestCreate for Keccak256 {
    const NAME: &'static str = "keccak-256";

    fn compute(&mut self, input: &[u8]) -> String {
        create(self, input)
    }
}

impl DigestCreate for Keccak256Full {
    const NAME: &'static str = "keccak-256-full";

    fn compute(&mut self, input: &[u8]) -> String {
        create(self, input)
    }
}

impl DigestCreate for Keccak384 {
    const NAME: &'static str = "keccak-384";

    fn compute(&mut self, input: &[u8]) -> String {
        create(self, input)
    }
}

impl DigestCreate for Keccak512 {
    const NAME: &'static str = "keccak-512";

    fn compute(&mut self, input: &[u8]) -> String {
        create(self, input)
    }
}
