use crate::impl_from_uint_for;
use num_bigint::BigUint;
use num_traits::ToPrimitive;
use serde::{Deserialize, Serialize};
use std::fmt::Display;

/// Signature schema
///
/// Note: u8 is enough for the signature schema
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Hash, Ord, PartialOrd, Copy)]
pub enum SignatureSchema {
    ECDSA = 10,
    EDDSA = 20,
}

impl SignatureSchema {
    /// Get the value of the signature schema
    pub fn value(&self) -> u8 {
        match self {
            SignatureSchema::ECDSA => 10,
            SignatureSchema::EDDSA => 20,
        }
    }
}

impl Display for SignatureSchema {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            SignatureSchema::ECDSA => write!(f, "ECDSA"),
            SignatureSchema::EDDSA => write!(f, "EDDSA"),
        }
    }
}

impl From<BigUint> for SignatureSchema {
    fn from(value: BigUint) -> Self {
        match value.to_u8().unwrap() {
            10 => SignatureSchema::ECDSA,
            20 => SignatureSchema::EDDSA,
            _ => panic!("Invalid signature schema"),
        }
    }
}

impl_from_uint_for!(SignatureSchema, u8, u16, u32, u64, u128);

#[cfg(test)]
mod tests {
    use super::*;
    use ex3_serde::{bincode, cbor};
    #[test]
    fn test_signature_schema_serde() {
        let schema = SignatureSchema::ECDSA;

        let bytes = bincode::serialize(&schema).unwrap();
        let schema2: SignatureSchema = bincode::deserialize(&bytes).unwrap();

        assert_eq!(schema, schema2);

        let schema = SignatureSchema::EDDSA;
        let bytes = cbor::serialize(&schema).unwrap();
        let schema2: SignatureSchema = cbor::deserialize(&bytes).unwrap();

        assert_eq!(schema, schema2);
    }
}
