use crate::dsnp::dsnp_types::{
	DsnpInnerGraph, DsnpPublicKey, DsnpUserPrivateGraphChunk, DsnpUserPublicGraphChunk,
};
use apache_avro::{from_avro_datum, from_value, to_avro_datum, to_value, Schema};
use dsnp_graph_config::errors::DsnpGraphResult;
use log::Level;
use log_result_proc_macro::log_result_err;
use serde::{Deserialize, Serialize};
pub struct SchemaHandler;
impl SchemaHandler {
	#[log_result_err(Level::Info)]
	pub fn read_public_key(data: &[u8]) -> DsnpGraphResult<DsnpPublicKey> {
		Self::read(data, &dsnp_graph_config::PUBLIC_KEY_SCHEMA)
	}
	#[log_result_err(Level::Info)]
	pub fn write_public_key(key: &DsnpPublicKey) -> DsnpGraphResult<Vec<u8>> {
		Self::write(key, &dsnp_graph_config::PUBLIC_KEY_SCHEMA)
	}
	#[log_result_err(Level::Info)]
	pub fn read_public_graph_chunk(data: &[u8]) -> DsnpGraphResult<DsnpUserPublicGraphChunk> {
		Self::read(data, &dsnp_graph_config::PUBLIC_GRAPH_CHUNK_SCHEMA)
	}
	#[log_result_err(Level::Info)]
	pub fn write_public_graph_chunk(chunk: &DsnpUserPublicGraphChunk) -> DsnpGraphResult<Vec<u8>> {
		Self::write(chunk, &dsnp_graph_config::PUBLIC_GRAPH_CHUNK_SCHEMA)
	}
	#[log_result_err(Level::Info)]
	pub fn read_inner_graph(data: &[u8]) -> DsnpGraphResult<DsnpInnerGraph> {
		Self::read(data, &dsnp_graph_config::PUBLIC_GRAPH_SCHEMA)
	}
	#[log_result_err(Level::Info)]
	pub fn write_inner_graph(inner_graph: &DsnpInnerGraph) -> DsnpGraphResult<Vec<u8>> {
		Self::write(inner_graph, &dsnp_graph_config::PUBLIC_GRAPH_SCHEMA)
	}
	#[log_result_err(Level::Info)]
	pub fn read_private_graph_chunk(data: &[u8]) -> DsnpGraphResult<DsnpUserPrivateGraphChunk> {
		Self::read(data, &dsnp_graph_config::PRIVATE_GRAPH_CHUNK_SCHEMA)
	}
	#[log_result_err(Level::Info)]
	pub fn write_private_graph_chunk(
		chunk: &DsnpUserPrivateGraphChunk,
	) -> DsnpGraphResult<Vec<u8>> {
		Self::write(chunk, &dsnp_graph_config::PRIVATE_GRAPH_CHUNK_SCHEMA)
	}
	#[log_result_err(Level::Info)]
	fn read<Output>(data: &[u8], schema: &Schema) -> DsnpGraphResult<Output>
	where
		Output: for<'a> Deserialize<'a>,
	{
		let reader = from_avro_datum(schema, &mut &data[..], None)?;
		Ok(from_value::<Output>(&reader)?)
	}
	#[log_result_err(Level::Info)]
	fn write<Input>(input: &Input, schema: &Schema) -> DsnpGraphResult<Vec<u8>>
	where
		Input: Serialize,
	{
		let val = to_value(input)?;
		Ok(to_avro_datum(schema, val)?)
	}
}
#[cfg(test)]
mod test {
	use super::*;
	use crate::dsnp::dsnp_types::{DsnpGraphEdge, DsnpPrid};
	use apache_avro::Error as AvroError;
	use dryoc::keypair::StackKeyPair;
	use dsnp_graph_config::errors::DsnpGraphError;
	#[test]
	fn public_key_read_and_write_using_valid_input_should_succeed() {
		let key = DsnpPublicKey { key_id: None, key: StackKeyPair::gen().public_key.to_vec() };
		let serialized = SchemaHandler::write_public_key(&key).expect("should serialize");
		let deserialized = SchemaHandler::read_public_key(&serialized).expect("should deserialize");
		assert_eq!(deserialized, key);
	}
	#[test]
	fn public_key_read_using_invalid_input_should_fail() {
		let key = DsnpPublicKey { key_id: None, key: b"217678127812871812334324".to_vec() };
		let mut serialized = SchemaHandler::write_public_key(&key).expect("should serialize");
		serialized[0] = !serialized[0]; let deserialized = SchemaHandler::read_public_key(&serialized);
		assert!(deserialized.is_err());
		assert!(matches!(
			deserialized.unwrap_err(),
			DsnpGraphError::AvroError(AvroError::ConvertI64ToUsize(_, _))
		));
	}
	#[test]
	fn public_graph_chunk_read_and_write_using_valid_input_should_succeed() {
		let chunk = DsnpUserPublicGraphChunk {
			compressed_public_graph: b"shugdua781262876euwsdgjdgjay981613789y1278eywhgdjhs"
				.to_vec(),
		};
		let serialized = SchemaHandler::write_public_graph_chunk(&chunk).expect("should serialize");
		let deserialized =
			SchemaHandler::read_public_graph_chunk(&serialized).expect("should deserialize");
		assert_eq!(deserialized, chunk);
	}
	#[test]
	fn inner_graph_read_and_write_using_valid_input_should_succeed() {
		let inner_graph: DsnpInnerGraph = vec![
			DsnpGraphEdge { user_id: 7, since: 12638718 },
			DsnpGraphEdge { user_id: 167282, since: 28638718 },
		];
		let serialized = SchemaHandler::write_inner_graph(&inner_graph).expect("should serialize");
		let deserialized =
			SchemaHandler::read_inner_graph(&serialized).expect("should deserialize");
		assert_eq!(deserialized, inner_graph);
	}
	#[test]
	fn private_graph_chunk_read_and_write_using_valid_input_should_succeed() {
		let chunk = DsnpUserPrivateGraphChunk {
			encrypted_compressed_private_graph:
				b"shugdua781262876euwsdgjdgjay981613789y1278eywhgdjhs".to_vec(),
			key_id: 26783,
			prids: vec![
				DsnpPrid::new(27737272u64.to_le_bytes().as_slice()),
				DsnpPrid::new(17237271u64.to_le_bytes().as_slice()),
			],
		};
		let serialized =
			SchemaHandler::write_private_graph_chunk(&chunk).expect("should serialize");
		let deserialized =
			SchemaHandler::read_private_graph_chunk(&serialized).expect("should deserialize");
		assert_eq!(deserialized, chunk);
	}
}