use super::{Key, KeyType};
use std::fmt;

use serde::de::{self, MapAccess, SeqAccess, Visitor};
use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};

impl Serialize for Key {
	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
	where
		S: Serializer,
	{
		let mut state = serializer.serialize_struct("Key", 2)?;
		state.serialize_field("tt", &self.tt)?;
		state.serialize_field(
			"key",
			&unsafe {
				match self.tt {
					KeyType::Aes128 => &self.key._32 as &[u8],
					KeyType::Aes256 => &self.key._64 as &[u8],
				}
			}.iter()
				.map(|i| *i as i32)
				.collect::<Vec<i32>>(),
		)?;

		state.end()
	}
}

impl<'de> Deserialize<'de> for Key {
	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
	where
		D: Deserializer<'de>,
	{
		#[derive(Deserialize)]
		#[serde(field_identifier, rename_all = "lowercase")]
		enum Field {
			Tt,
			Key,
		};

		struct KeyVisitor;

		impl<'de> Visitor<'de> for KeyVisitor {
			type Value = Key;

			fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
				formatter.write_str("struct Key")
			}

			fn visit_seq<V>(self, mut seq: V) -> Result<Key, V::Error>
			where
				V: SeqAccess<'de>,
			{
				use super::KeyBuf;
				let tt: KeyType = seq
					.next_element()?
					.ok_or_else(|| de::Error::invalid_length(0, &self))?;
				let raw_key: Vec<i32> = seq
					.next_element()?
					.ok_or_else(|| de::Error::invalid_length(1, &self))?;

				let mut key = match tt {
					KeyType::Aes128 => KeyBuf { _32: [0u8; 32] },
					KeyType::Aes256 => KeyBuf { _64: [0u8; 64] },
				};

				let len = raw_key.len();
				for i in 0..len {
					unsafe {
						match tt {
							KeyType::Aes128 => key._32[i] = raw_key[i] as u8,
							KeyType::Aes256 => key._64[i] = raw_key[i] as u8,
						};
					}
				}

				Ok(Key { tt, key })
			}

			fn visit_map<V>(self, mut map: V) -> Result<Key, V::Error>
			where
				V: MapAccess<'de>,
			{
				let mut tt: Option<KeyType> = None;
				let mut raw_key: Option<Vec<i32>> = None;

				while let Some(k) = map.next_key()? {
					match k {
						Field::Tt => {
							if tt.is_some() {
								return Err(de::Error::duplicate_field("tt"));
							}
							tt = Some(map.next_value()?);
						}
						Field::Key => {
							if raw_key.is_some() {
								return Err(de::Error::duplicate_field("key"));
							}
							raw_key = Some(map.next_value()?);
						}
					}
				}

				/* Validate the inputs */
				let tt = tt.ok_or_else(|| de::Error::missing_field("tt"))?;
				let raw_key = raw_key.ok_or_else(|| de::Error::missing_field("key"))?;

				/* Construct an empty key */
				use super::KeyBuf;
				let mut key = match tt {
					KeyType::Aes128 => KeyBuf { _32: [0u8; 32] },
					KeyType::Aes256 => KeyBuf { _64: [0u8; 64] },
				};

				let len = raw_key.len();
				for i in 0..len {
					unsafe {
						match tt {
							KeyType::Aes128 => key._32[i] = raw_key[i] as u8,
							KeyType::Aes256 => key._64[i] = raw_key[i] as u8,
						};
					}
				}

				Ok(Key { tt, key })
			}
		}

		const FIELDS: &[&str] = &["tt", "key"];
		deserializer.deserialize_struct("Key", FIELDS, KeyVisitor)
	}
}
