use crate::ffi;
use crate::error::{check, Error};
use crate::keypair::Keypair;

pub fn sign(kp: &Keypair, msg: &[u8]) -> Result<[u8; 64], Error> {
    let mut sig = [0u8; 64];
    check(unsafe { ffi::nwep_sign(sig.as_mut_ptr(), msg.as_ptr(), msg.len(), kp.as_ffi()) })?;
    Ok(sig)
}

pub fn verify(pubkey: &[u8; 32], sig: &[u8; 64], msg: &[u8]) -> Result<(), Error> {
    check(unsafe { ffi::nwep_verify(sig.as_ptr(), msg.as_ptr(), msg.len(), pubkey.as_ptr()) })
}

pub fn challenge_generate() -> Result<[u8; 32], Error> {
    let mut ch = [0u8; 32];
    check(unsafe { ffi::nwep_challenge_generate(ch.as_mut_ptr()) })?;
    Ok(ch)
}

pub fn challenge_sign(challenge: &[u8; 32], kp: &Keypair) -> Result<[u8; 64], Error> {
    let mut response = [0u8; 64];
    check(unsafe { ffi::nwep_challenge_sign(response.as_mut_ptr(), challenge.as_ptr(), kp.as_ffi()) })?;
    Ok(response)
}

pub fn challenge_verify(response: &[u8; 64], challenge: &[u8; 32], pubkey: &[u8; 32]) -> Result<(), Error> {
    check(unsafe { ffi::nwep_challenge_verify(response.as_ptr(), challenge.as_ptr(), pubkey.as_ptr()) })
}

pub fn random_bytes(dest: &mut [u8]) -> Result<(), Error> {
    check(unsafe { ffi::nwep_random_bytes(dest.as_mut_ptr(), dest.len()) })
}

#[derive(Clone, Debug)]
pub struct ShamirShare {
    pub index: u8,
    pub data: [u8; 32],
}

pub fn shamir_split(secret: &[u8; 32], n: usize, t: usize) -> Result<Vec<ShamirShare>, Error> {
    let mut shares = vec![ffi::nwep_shamir_share { index: 0, data: [0u8; 32] }; n];
    check(unsafe { ffi::nwep_shamir_split(secret.as_ptr(), shares.as_mut_ptr(), n, t) })?;
    Ok(shares
        .into_iter()
        .map(|s| ShamirShare { index: s.index, data: s.data })
        .collect())
}

pub fn shamir_combine(shares: &[ShamirShare]) -> Result<[u8; 32], Error> {
    let ffi_shares: Vec<ffi::nwep_shamir_share> = shares
        .iter()
        .map(|s| ffi::nwep_shamir_share { index: s.index, data: s.data })
        .collect();
    let mut secret = [0u8; 32];
    check(unsafe { ffi::nwep_shamir_combine(secret.as_mut_ptr(), ffi_shares.as_ptr(), ffi_shares.len()) })?;
    Ok(secret)
}
