use fn_dsa::{
    SigningKey, SigningKeyStandard, VerifyingKey, VerifyingKeyStandard, DOMAIN_NONE, HASH_ID_RAW,
};
use rand::thread_rng;
use skein::digest::consts::{U32, U64};
use skein::digest::{Digest, Output};
use skein::{Skein256, Skein512};

use crate::error::BrowserCoreError;
use crate::SIGNATURE_LENGTH;

pub fn skein_128(data: &[u8]) -> Vec<u8> {
    let mut hasher = Skein256::new();
    hasher.update(data);
    let result: Output<Skein256> = hasher.finalize();
    result.iter().step_by(2).copied().collect()
}

pub fn skein_256(data: &[u8]) -> Vec<u8> {
    let mut hasher = Skein256::<U32>::new();
    hasher.update(data);
    hasher.finalize().to_vec()
}

pub fn skein_512(data: &[u8]) -> Vec<u8> {
    let mut hasher = Skein512::<U64>::new();
    hasher.update(data);
    hasher.finalize().to_vec()
}

pub fn sign(message: &[u8], private_key: &[u8]) -> Result<Vec<u8>, BrowserCoreError> {
    let mut signing_key =
        SigningKeyStandard::decode(private_key).ok_or(BrowserCoreError::InvalidPrivateKey)?;
    let mut signature = vec![0u8; SIGNATURE_LENGTH];
    let mut rng = thread_rng();
    signing_key.sign(
        &mut rng,
        &DOMAIN_NONE,
        &HASH_ID_RAW,
        message,
        &mut signature,
    );
    Ok(signature)
}

pub fn verify(message: &[u8], signature: &[u8], public_key: &[u8]) -> bool {
    if signature.len() != SIGNATURE_LENGTH {
        return false;
    }
    let Some(verifying_key) = VerifyingKeyStandard::decode(public_key) else {
        return false;
    };
    verifying_key.verify(signature, &DOMAIN_NONE, &HASH_ID_RAW, message)
}
