Documentation
use data_encoding::BASE64URL_NOPAD;
use liter::Value;
use rand::Rng;
use serde::{Serialize, Deserialize};


#[derive(
	Copy,
	Clone,
	PartialEq,
	Eq,
	PartialOrd,
	Ord,
	Hash,
	Serialize,
	Deserialize,
	Value
)]
pub struct NodeID {
	id: [u8; 6]
}

impl NodeID {

	pub fn get(self) -> [u8; 6] { self.id }
	/// Generate a random NodeID according to RFC4122 Section 4.5
	pub fn random() -> Self {
		let mut id: [u8; 6] = rand::rng().random();
		// "The least significant bit of the first octet set to one"
		id[0] |= 0b1;
		Self {id}
	}
	pub fn inner(&self) -> &[u8; 6] {&self.id}
	pub fn from_u64(packed: u64) -> Self {
		let [_, _, a, b, c, d, e, f] = packed.to_le_bytes();
		Self { id: [a, b, c, d, e, f] }
	}
	pub fn to_u64(self) -> u64 {
		let Self { id: [a, b, c, d, e, f]} = self;
		u64::from_le_bytes([0, 0, a, b, c, d, e, f])
	}
}

/*
 *	NODE ID CONVERSION TRAITS
 */

impl std::ops::Deref for NodeID {
	type Target = [u8];
	fn deref(&self) -> &[u8] {&self.id}
}
impl std::convert::AsRef<[u8; 6]> for NodeID {
	fn as_ref(&self) -> &[u8; 6] {&self.id}
}
impl std::convert::AsMut<[u8; 6]> for NodeID {
	fn as_mut(&mut self) -> &mut [u8; 6] {&mut self.id}
}

impl std::convert::From<[u8; 6]> for NodeID {
	fn from(id: [u8; 6]) -> Self {Self{id}}
}
impl std::convert::From<NodeID> for [u8; 6] {
	fn from(node_id: NodeID) -> [u8; 6] {node_id.id}
}

impl std::str::FromStr for NodeID {
	type Err = String;

	fn from_str(s: &str) -> Result<Self, Self::Err> {
		match BASE64URL_NOPAD.decode(s.as_bytes()) {
			Ok(id_vec) if id_vec.len() == 6 => {
				Ok(Self {id: id_vec.try_into().unwrap()})
			},
			Ok(_) => Err("ID is not exactly 6 bytes long!".to_owned()),
			Err(e) => Err(
				format!("failed to decode URL-safe base64 ID: {e}")
			)
		}
	}
}
impl std::fmt::Display for NodeID {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		BASE64URL_NOPAD.encode(&self.id).fmt(f)
	}
}
impl std::fmt::Debug for NodeID {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		std::fmt::Display::fmt(self, f)
	}
}