//! Signature-related types and traits

use std::{rc::Rc, sync::Arc};

/// Describe the operation of signing a string
///
/// This is used by downstream crates for creating HTTP Signatures.
pub trait Sign {
    /// Errors that signing the request can produce
    type Error: Send;

    /// Sign the given string, producing a String
    fn sign(&self, signing_string: &str) -> Result<String, Self::Error>;
}

/// Describes creating signatures
pub trait PrivateKey {
    /// The type that actually signs requests
    type Signer: Sign + Send + 'static;

    /// Get the KeyId from the factory
    fn key_id(&self) -> String;

    /// Produce the type that actually signs the request
    fn signer(&self) -> Self::Signer;
}

/// Describes building private keys
pub trait PrivateKeyBuilder: PrivateKey {
    /// Errors possible when constructing private keys
    type Error: Send;

    /// Build private key from pem pkcs8
    fn build(key_id: String, private_key_pem: &str) -> Result<Self, Self::Error>
    where
        Self: Sized;
}

/// Describes verifying signatures
pub trait Verify {
    /// Errors that verifying a signature can produce
    type Error: Send;

    /// Verify the signature matches the provided signing string
    fn verify(&self, signing_string: &str, signature: &str) -> Result<bool, Self::Error>;
}

/// Describes a marker type that is associated with a specific verifier
pub trait VerifyFactory {
    /// The Verify type associated with this factory
    type Verify: Verify + VerifyBuilder;
}

/// Describes creating Verifiers
pub trait VerifyBuilder: Verify {
    /// Build a verifier from a given public key in pem format
    fn build(public_key_pem: &str) -> Result<Self, Self::Error>
    where
        Self: Sized;
}

impl<'a, T> Verify for &'a T
where
    T: Verify,
{
    type Error = T::Error;

    fn verify(&self, signing_string: &str, signature: &str) -> Result<bool, Self::Error> {
        T::verify(self, signing_string, signature)
    }
}

impl<'a, T> Verify for &'a mut T
where
    T: Verify,
{
    type Error = T::Error;

    fn verify(&self, signing_string: &str, signature: &str) -> Result<bool, Self::Error> {
        T::verify(self, signing_string, signature)
    }
}

impl<T> Verify for Box<T>
where
    T: Verify,
{
    type Error = T::Error;

    fn verify(&self, signing_string: &str, signature: &str) -> Result<bool, Self::Error> {
        T::verify(self, signing_string, signature)
    }
}

impl<T> Verify for Rc<T>
where
    T: Verify,
{
    type Error = T::Error;

    fn verify(&self, signing_string: &str, signature: &str) -> Result<bool, Self::Error> {
        T::verify(self, signing_string, signature)
    }
}

impl<T> Verify for Arc<T>
where
    T: Verify,
{
    type Error = T::Error;

    fn verify(&self, signing_string: &str, signature: &str) -> Result<bool, Self::Error> {
        T::verify(self, signing_string, signature)
    }
}

impl<'a, T> Sign for &'a T
where
    T: Sign,
{
    type Error = T::Error;

    fn sign(&self, signing_string: &str) -> Result<String, Self::Error> {
        T::sign(self, signing_string)
    }
}

impl<'a, T> Sign for &'a mut T
where
    T: Sign,
{
    type Error = T::Error;

    fn sign(&self, signing_string: &str) -> Result<String, Self::Error> {
        T::sign(self, signing_string)
    }
}

impl<T> Sign for Box<T>
where
    T: Sign,
{
    type Error = T::Error;

    fn sign(&self, signing_string: &str) -> Result<String, Self::Error> {
        T::sign(self, signing_string)
    }
}

impl<T> Sign for Rc<T>
where
    T: Sign,
{
    type Error = T::Error;

    fn sign(&self, signing_string: &str) -> Result<String, Self::Error> {
        T::sign(self, signing_string)
    }
}

impl<T> Sign for Arc<T>
where
    T: Sign,
{
    type Error = T::Error;

    fn sign(&self, signing_string: &str) -> Result<String, Self::Error> {
        T::sign(self, signing_string)
    }
}

impl<'a, T> PrivateKey for &'a T
where
    T: PrivateKey,
{
    type Signer = T::Signer;

    fn key_id(&self) -> String {
        T::key_id(self)
    }

    fn signer(&self) -> Self::Signer {
        T::signer(self)
    }
}

impl<'a, T> PrivateKey for &'a mut T
where
    T: PrivateKey,
{
    type Signer = T::Signer;

    fn key_id(&self) -> String {
        T::key_id(self)
    }

    fn signer(&self) -> Self::Signer {
        T::signer(self)
    }
}

impl<T> PrivateKey for Box<T>
where
    T: PrivateKey,
{
    type Signer = T::Signer;

    fn key_id(&self) -> String {
        T::key_id(self)
    }

    fn signer(&self) -> Self::Signer {
        T::signer(self)
    }
}

impl<T> PrivateKey for Rc<T>
where
    T: PrivateKey,
{
    type Signer = T::Signer;

    fn key_id(&self) -> String {
        T::key_id(self)
    }

    fn signer(&self) -> Self::Signer {
        T::signer(self)
    }
}

impl<T> PrivateKey for Arc<T>
where
    T: PrivateKey,
{
    type Signer = T::Signer;

    fn key_id(&self) -> String {
        T::key_id(self)
    }

    fn signer(&self) -> Self::Signer {
        T::signer(self)
    }
}
