//! Defines a simple header for serialization and deserialization of messages. Should be used for
//! all messages sent between the client and server.
use nanoservices_utils::errors::{NanoServiceError, NanoServiceErrorStatus};

use crate::messages::serialization::traits::IntoVecBytes;

// To define the size of the message.
pub type MessageHeader = Header<usize>;

/// A simple header struct to be used for serialization and deserialization of messages.
///
#[derive(Debug, PartialEq)]
pub struct Header<T: Sized + IntoVecBytes + Clone> {
	pub value: T,
}

impl<T: Sized + IntoVecBytes + Clone> Header<T> {
	/// Converts the header into a vector of bytes.
	///
	/// # Returns
	/// a vector of bytes representing the header
	pub fn to_bytes(&self) -> Vec<u8> {
		T::to_be_bytes(self.value.clone())
	}
}

impl Header<usize> {
	/// Converts a slice of bytes into a message header.
	///
	/// # Arguments
	/// * `bytes`: the vector of bytes to be converted
	///
	/// # Returns
	/// the message header
	pub fn from_bytes(bytes: &[u8; 8]) -> MessageHeader {
		MessageHeader {
			value: usize::from_be_bytes([
				bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
			]),
		}
	}

	/// Converts a vector of bytes into a message header.
	///
	/// # Arguments
	/// * `bytes`: the vector of bytes to be converted
	///
	/// # Returns
	/// the message header
	pub fn from_vector_bytes(bytes: Vec<u8>) -> Result<MessageHeader, NanoServiceError> {
		if bytes.len() != 8 {
			return Err(NanoServiceError::new(
				format!("Invalid byte length for meta header {}, should be 8", bytes.len()),
				NanoServiceErrorStatus::BadRequest,
			));
		}
		Ok(MessageHeader {
			value: usize::from_be_bytes([
				bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
			]),
		})
	}
}

#[cfg(test)]
mod tests {
	use super::*;

	#[test]
	fn test_message_header() {
		let header = MessageHeader {
			value: 5,
		};
		let bytes = header.to_bytes();
		assert_eq!(bytes.len(), 8);
		let header = MessageHeader::from_bytes(&[
			bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
		]);
		assert_eq!(header.value, 5);
	}

	#[test]
	fn test_message_header_from_vector_bytes() {
		let header = MessageHeader::from_vector_bytes(vec![0, 0, 0, 0, 0, 0, 0, 5]).unwrap();
		assert_eq!(header.value, 5);
	}

	#[test]
	fn test_message_header_from_vector_bytes_invalid() {
		let header = MessageHeader::from_vector_bytes(vec![0, 0, 0, 0, 0, 0, 0, 5, 6]);
		assert!(header.is_err());
	}
}
