#[macro_export]
macro_rules! new_hash_type {
	($t:ident) => {
		$crate::new_key_type!($t, 32);
	};
}

#[macro_export]
macro_rules! new_key_type {
	($t:ident , $l:expr) => {
		#[derive(
			$crate::Encode,
			$crate::Decode,
			$crate::MaxEncodedLen,
			Copy,
			Clone,
			Eq,
			PartialEq,
			Ord,
			PartialOrd,
			Hash,
		)]
		#[repr(transparent)]
		pub struct $t(pub [u8; $l]);

		impl scale::ConstEncodedLen for $t {}

		impl Default for $t {
			fn default() -> Self {
				Self([0; $l])
			}
		}

		impl core::ops::Deref for $t {
			type Target = [u8; $l];
			fn deref(&self) -> &Self::Target {
				&self.0
			}
		}

		impl core::ops::DerefMut for $t {
			fn deref_mut(&mut self) -> &mut Self::Target {
				&mut self.0
			}
		}

		impl From<[u8; $l]> for $t {
			fn from(value: [u8; $l]) -> Self {
				Self(value)
			}
		}
		impl AsRef<[u8; $l]> for $t {
			fn as_ref(&self) -> &[u8; $l] {
				&self.0
			}
		}
		impl AsMut<[u8; $l]> for $t {
			fn as_mut(&mut self) -> &mut [u8; $l] {
				&mut self.0
			}
		}
		impl AsMut<[u8]> for $t {
			fn as_mut(&mut self) -> &mut [u8] {
				&mut self.0[..]
			}
		}

		impl core::fmt::Debug for $t {
			fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
				if self.iter().all(|&x| x > 31 && x < 127 || x == 0) {
					f.write_fmt(format_args!("\"{}\"", core::str::from_utf8(&self.0).unwrap()))
				} else if self.0.len() > 8 {
					f.write_fmt(format_args!(
						"0x{}..{}",
						$crate::hex::hex(&self.0[..8]),
						$crate::hex::hex(&self.0[self.0.len() - 4..])
					))
				} else {
					f.write_fmt(format_args!("0x{}", $crate::hex::hex(&self.0)))
				}
			}
		}

		impl core::fmt::Display for $t {
			fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
				if self.iter().all(|&x| x > 31 && x < 127 || x == 0) {
					f.write_fmt(format_args!("\"{}\"", core::str::from_utf8(&self.0).unwrap()))
				} else if self.0.len() > 8 {
					f.write_fmt(format_args!(
						"0x{}..{}",
						$crate::hex::hex(&self.0[..8]),
						$crate::hex::hex(&self.0[self.0.len() - 4..])
					))
				} else {
					f.write_fmt(format_args!("0x{}", $crate::hex::hex(&self.0)))
				}
			}
		}

		impl $t {
			pub fn zero() -> Self {
				Self([0; $l])
			}
			pub fn padded(left: &[u8]) -> Self {
				let mut i = [0; $l];
				i[..left.len().min($l)].copy_from_slice(&left[..left.len().min($l)]);
				Self(i)
			}
			pub const fn len() -> usize {
				$l
			}
			pub fn to_vec(&self) -> $crate::Vec<u8> {
				self.0.to_vec()
			}

			pub const LEN: usize = $l;
		}

		impl From<$t> for [u8; $l] {
			fn from(value: $t) -> [u8; $l] {
				value.0
			}
		}
	};
}

#[macro_export]
macro_rules! new_vec_type {
	($t:ident) => {
		#[derive(
			$crate::Encode, $crate::Decode, Default, Clone, Eq, PartialEq, Ord, PartialOrd,
		)]
		pub struct $t(pub $crate::Vec<u8>);

		impl core::ops::Deref for $t {
			type Target = $crate::Vec<u8>;
			fn deref(&self) -> &Self::Target {
				&self.0
			}
		}

		impl core::ops::DerefMut for $t {
			fn deref_mut(&mut self) -> &mut Self::Target {
				&mut self.0
			}
		}

		impl From<$crate::Vec<u8>> for $t {
			fn from(value: $crate::Vec<u8>) -> Self {
				Self(value)
			}
		}

		impl $t {
			pub fn new() -> Self {
				Self($crate::Vec::new())
			}
			pub fn take(self) -> $crate::Vec<u8> {
				self.0
			}
		}

		impl From<$t> for $crate::Vec<u8> {
			fn from(other: $t) -> Self {
				other.0
			}
		}

		impl core::fmt::Debug for $t {
			fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
				core::fmt::Display::fmt(self, f)
			}
		}

		impl core::fmt::Display for $t {
			fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
				let suffix = self.iter().rev().take_while(|&&x| x == 0).count();
				let body = &self.0[..self.len() - suffix];
				if body.len() > 32 {
					f.write_fmt(format_args!(
						"0x{}..{}",
						$crate::hex::hex(&body[..8]),
						$crate::hex::hex(&body[body.len() - 4..])
					))?;
				} else if body.iter().all(|&x| x > 31 && x < 127) {
					f.write_fmt(format_args!("\"{}\"", core::str::from_utf8(body).unwrap()))?;
				} else {
					f.write_fmt(format_args!("0x{}", $crate::hex::hex(body)))?;
				}
				if suffix != 0 {
					f.write_fmt(format_args!("+{suffix}*0"))?;
				}
				Ok(())
			}
		}
	};
}

#[macro_export]
macro_rules! new_bounded_vec_type {
	($t:ident, $s:expr) => {
		#[derive(
			$crate::Encode,
			$crate::Decode,
			$crate::MaxEncodedLen,
			Default,
			Clone,
			Eq,
			PartialEq,
			Ord,
			PartialOrd,
		)]
		pub struct $t(pub $crate::BoundedVec<u8, ConstU32<{ $s as u32 }>>);

		impl core::ops::Deref for $t {
			type Target = $crate::BoundedVec<u8, ConstU32<{ $s as u32 }>>;
			fn deref(&self) -> &Self::Target {
				&self.0
			}
		}

		impl core::ops::DerefMut for $t {
			fn deref_mut(&mut self) -> &mut Self::Target {
				&mut self.0
			}
		}

		impl TryFrom<$crate::Vec<u8>> for $t {
			type Error = ();
			fn try_from(value: $crate::Vec<u8>) -> Result<Self, Self::Error> {
				Ok(Self($crate::BoundedVec::try_from(value).map_err(|_| ())?))
			}
		}

		impl From<$crate::BoundedVec<u8, ConstU32<{ $s as u32 }>>> for $t {
			fn from(value: $crate::BoundedVec<u8, ConstU32<{ $s as u32 }>>) -> Self {
				Self(value)
			}
		}

		impl core::fmt::Debug for $t {
			fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
				core::fmt::Display::fmt(self, f)
			}
		}

		impl core::fmt::Display for $t {
			fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
				if self.0.len() > 32 {
					f.write_fmt(format_args!(
						"0x{}..{}",
						$crate::hex::hex(&self.0[..8]),
						$crate::hex::hex(&self.0[self.0.len() - 4..])
					))
				} else {
					f.write_fmt(format_args!("0x{}", $crate::hex::hex(&self.0)))
				}
			}
		}
	};
}
