use std::marker::PhantomData;

use serde::{
	Deserialize, Serialize,
	ser::{SerializeMap, SerializeSeq},
};

use crate::{BTreeIndexMap, BTreeIndexMultiMap, BTreeIndexMultiSet, BTreeIndexSet};

impl<K: Serialize, V: Serialize> Serialize for BTreeIndexMap<K, V> {
	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
	where
		S: serde::Serializer,
	{
		let mut map = serializer.serialize_map(Some(self.len()))?;

		for (key, value) in self {
			map.serialize_entry(key, value)?;
		}

		map.end()
	}
}

impl<'de, K: Ord + Deserialize<'de>, V: Deserialize<'de>> Deserialize<'de> for BTreeIndexMap<K, V> {
	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
	where
		D: serde::Deserializer<'de>,
	{
		struct Visitor<K, V>(PhantomData<(K, V)>);

		impl<'de, K, V> serde::de::Visitor<'de> for Visitor<K, V>
		where
			K: Ord + Deserialize<'de>,
			V: Deserialize<'de>,
		{
			type Value = BTreeIndexMap<K, V>;

			fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
				write!(formatter, "a map")
			}

			fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
			where
				A: serde::de::MapAccess<'de>,
			{
				let mut result = BTreeIndexMap::new();

				while let Some((key, value)) = map.next_entry()? {
					result.insert(key, value);
				}

				Ok(result)
			}
		}

		deserializer.deserialize_map(Visitor(PhantomData))
	}
}

impl<K: Serialize, V: Serialize> Serialize for BTreeIndexMultiMap<K, V> {
	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
	where
		S: serde::Serializer,
	{
		let mut map = serializer.serialize_map(Some(self.len()))?;

		for (key, value) in self {
			map.serialize_entry(key, value)?;
		}

		map.end()
	}
}

impl<'de, K: Ord + Deserialize<'de>, V: Deserialize<'de>> Deserialize<'de>
	for BTreeIndexMultiMap<K, V>
{
	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
	where
		D: serde::Deserializer<'de>,
	{
		struct Visitor<K, V>(PhantomData<(K, V)>);

		impl<'de, K, V> serde::de::Visitor<'de> for Visitor<K, V>
		where
			K: Ord + Deserialize<'de>,
			V: Deserialize<'de>,
		{
			type Value = BTreeIndexMultiMap<K, V>;

			fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
				write!(formatter, "a map")
			}

			fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
			where
				A: serde::de::MapAccess<'de>,
			{
				let mut result = BTreeIndexMultiMap::new();

				// `push_back`, not `insert`: duplicate keys must be
				// preserved as distinct entries.
				while let Some((key, value)) = map.next_entry()? {
					result.push_back(key, value);
				}

				Ok(result)
			}
		}

		deserializer.deserialize_map(Visitor(PhantomData))
	}
}

impl<T: Serialize> Serialize for BTreeIndexSet<T> {
	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
	where
		S: serde::Serializer,
	{
		let mut seq = serializer.serialize_seq(Some(self.len()))?;

		for value in self {
			seq.serialize_element(value)?;
		}

		seq.end()
	}
}

impl<'de, T: Ord + Deserialize<'de>> Deserialize<'de> for BTreeIndexSet<T> {
	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
	where
		D: serde::Deserializer<'de>,
	{
		struct Visitor<T>(PhantomData<T>);

		impl<'de, T> serde::de::Visitor<'de> for Visitor<T>
		where
			T: Ord + Deserialize<'de>,
		{
			type Value = BTreeIndexSet<T>;

			fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
				write!(formatter, "a sequence")
			}

			fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
			where
				A: serde::de::SeqAccess<'de>,
			{
				let mut result = BTreeIndexSet::new();

				while let Some(value) = seq.next_element()? {
					result.insert(value);
				}

				Ok(result)
			}
		}

		deserializer.deserialize_seq(Visitor(PhantomData))
	}
}

impl<T: Serialize> Serialize for BTreeIndexMultiSet<T> {
	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
	where
		S: serde::Serializer,
	{
		let mut seq = serializer.serialize_seq(Some(self.len()))?;

		for value in self {
			seq.serialize_element(value)?;
		}

		seq.end()
	}
}

impl<'de, T: Ord + Deserialize<'de>> Deserialize<'de> for BTreeIndexMultiSet<T> {
	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
	where
		D: serde::Deserializer<'de>,
	{
		struct Visitor<T>(PhantomData<T>);

		impl<'de, T> serde::de::Visitor<'de> for Visitor<T>
		where
			T: Ord + Deserialize<'de>,
		{
			type Value = BTreeIndexMultiSet<T>;

			fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
				write!(formatter, "a sequence")
			}

			fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
			where
				A: serde::de::SeqAccess<'de>,
			{
				let mut result = BTreeIndexMultiSet::new();

				// `push_back`, not `insert`: duplicate values must be
				// preserved as distinct occurrences.
				while let Some(value) = seq.next_element()? {
					result.push_back(value);
				}

				Ok(result)
			}
		}

		deserializer.deserialize_seq(Visitor(PhantomData))
	}
}
