use crate::internal;
use quick_error::quick_error;
use rand::rngs::adapter::ReseedingRng;
use rand::rngs::OsRng;

quick_error! {
    /// Errors generated by the API
    #[derive(Debug, PartialEq)]
    pub enum RecryptErr {
        DecryptFailed(err: internal::InternalError){
            display("The decryption failed. Ensure you're using the correct PrivateKey.")
            source(err)
        }
        InvalidEncryptedMessageSignature(err: internal::InternalError){
            display("The signature of the encrypted value could not be verified.")
            source(err)
        }
        InvalidPublicKey(err: internal::homogeneouspoint::PointErr){
            display("The public key was not valid. Ensure it was generated from a valid PrivateKey.")
            from()
            source(err)
        }
        InvalidTransformKey(err: internal::InternalError){
            source(err)
            display("The transform key signature was incorrect.")
        }
        InputWrongSize(typ: &'static str, req_size: usize){
            display("The input value was the wrong size. Expected {} bytes for type {}.", req_size, typ)
        }
        DecodeFailure(err: internal::bytedecoder::DecodeErr){
            display("The bytes could not be decoded into the appropriate data type.")
            source(err)
            from()
        }
    }
}

pub type DefaultRng = ReseedingRng<rand_chacha::ChaChaCore, OsRng>;
pub type Result<T> = std::result::Result<T, RecryptErr>;

impl From<internal::InternalError> for RecryptErr {
    fn from(err: internal::InternalError) -> Self {
        match err {
            internal::InternalError::AuthHashMatchFailed => RecryptErr::DecryptFailed(err),
            internal::InternalError::InvalidEncryptedMessageSignature => {
                RecryptErr::InvalidEncryptedMessageSignature(err)
            }
            internal::InternalError::PointInvalid(p_err) => RecryptErr::InvalidPublicKey(p_err),
            internal::InternalError::CorruptReencryptionKey => RecryptErr::InvalidTransformKey(err),
        }
    }
}

#[cfg(test)]
pub(crate) mod test {
    use super::*;

    //Writing a BS from conversion to make tests which contain `hex` constants easier to write.
    impl From<hex::FromHexError> for RecryptErr {
        fn from(err: hex::FromHexError) -> Self {
            panic!("Error '{:?}' was found when parsing hex in tests.", err);
        }
    }
}
