//! Event signature
use serde::{
    de::{self, Deserialize, Deserializer},
    ser::{self, Serializer},
};
use std::{
    fmt::{self, Display},
    ops::Deref,
};
use thiserror::Error;

/// Errors
#[derive(Error, Debug)]
pub enum Error {
    /// Invalid JSON encoding
    ///
    /// It must be encoded as a hex string with length 128
    #[error("Error decoding: {0}")]
    DecodingError(#[from] hex::FromHexError),

    /// Invalid size of the signature
    #[error("Expecting a 64 bytes signature")]
    InvalidSize,
}

/// Wraps the signature as a 64-bytes vector of bytes
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Signature(pub [u8; 64]);

impl From<secp256k1::schnorr::Signature> for Signature {
    fn from(signature: secp256k1::schnorr::Signature) -> Self {
        Self(*signature.as_ref())
    }
}

impl AsRef<[u8]> for Signature {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl Deref for Signature {
    type Target = [u8; 64];
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl Display for Signature {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", hex::encode(self.0))
    }
}

impl TryFrom<String> for Signature {
    type Error = Error;

    fn try_from(value: String) -> Result<Self, Self::Error> {
        let bytes = hex::decode(value)?;
        if bytes.len() != 64 {
            return Err(Error::InvalidSize);
        }
        Ok(Self(
            bytes[0..64].try_into().map_err(|_| Error::InvalidSize)?,
        ))
    }
}

impl TryFrom<&str> for Signature {
    type Error = Error;

    fn try_from(value: &str) -> Result<Self, Self::Error> {
        value.to_owned().try_into()
    }
}

impl<'de> Deserialize<'de> for Signature {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = <String>::deserialize(deserializer)?;
        let t = s
            .try_into()
            .map_err(|e: Error| de::Error::custom(e.to_string()))?;
        Ok(t)
    }
}

impl ser::Serialize for Signature {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let str = self.to_string();
        serializer.serialize_str(&str)
    }
}
