use scale_info::TypeInfo;
use codec::{Encode, Decode};
use frame_support::{BoundedVec, traits::ConstU32};
use sp_runtime::{RuntimeDebug, traits::UniqueSaturatedInto};

type ExodusNonceT = BoundedVec<u8, ConstU32<{ crate::ELEMENT_MAX_BYTES }>>;
type ExodusSignatureT = BoundedVec<u8, ConstU32<{ crate::SCALAR_MAX_BYTES }>>;
type Type<NetworkId, Balance> = super::ExodusRequestType<NetworkId, Balance>;

#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, RuntimeDebug)]
pub struct ExodusSignedMessage<NetworkId: Default, Balance: Default> {
    pub nonce: ExodusNonceT,
    pub signature: ExodusSignatureT,
    pub r#type: Type<NetworkId, Balance>,
}

impl<NetworkId, Balance> ExodusSignedMessage<NetworkId, Balance>
where
	NetworkId: UniqueSaturatedInto<u64> + Copy + Default,
	Balance: UniqueSaturatedInto<u128> + Copy + Default,
{
    pub fn new<E, S>(
        nonce_iter: E,
        signature_iter: S,
        r#type: Type<NetworkId, Balance>
    ) -> Option<Self>
    where
		E: Iterator<Item = u8> + ExactSizeIterator,
		S: Iterator<Item = u8> + ExactSizeIterator,
	{
        let mut nonce = ExodusNonceT::new();
        nonce.try_extend(nonce_iter).ok()?;

        let mut signature = ExodusSignatureT::new();
        signature.try_extend(signature_iter).ok()?;

        Some(Self { nonce, signature, r#type })
    }

    pub fn get_message<'a>(
        &self,
        message_buffer: &'a mut [u8; crate::MAX_MESSAGE_SIZE as usize],
    ) -> Option<&'a [u8]> {
        self.r#type.get_message(message_buffer)
    }
}
