Documentation
use {
	crate::{Column, Glue, NullOrd, Result, Row, ValidateError, Value},
	std::cmp::Ordering,
};

macro_rules! some_or_continue {
	($option: expr) => {
		match $option {
			Some(value) => value,
			None => return Some(Ok(())),
		}
	};
}
macro_rules! some_or {
	($option: expr, $or: block) => {
		match $option {
			Some(value) => value,
			None => $or,
		}
	};
}

impl Glue {
	pub(crate) async fn validate_unique(
		&self,
		database: &Option<String>,
		table_name: &str,
		column_defs: &[Column],
		rows: &[Row],
		ignore_keys: Option<&[Value]>,
	) -> Result<()> {
		let unique_columns: Vec<usize> = column_defs
			.iter()
			.enumerate()
			.filter_map(|(index, column_def)| {
				if column_def.is_unique {
					Some(index)
				} else {
					None
				}
			})
			.collect();
		let mut existing_values: Vec<Vec<Value>> = vec![vec![]; unique_columns.len()];
		self.get_database(database)?
			.scan_data(table_name)
			.await?
			.into_iter()
			.try_for_each::<_, Result<_>>(|(key, row)| {
				if let Some(ignore_keys) = ignore_keys {
					if ignore_keys.iter().any(|ignore_key| ignore_key == &key) {
						return Ok(());
					}
				}
				let row = row.0;
				unique_columns
					.iter()
					.enumerate()
					.map(|(index, row_index)| {
						existing_values
							.get_mut(index)?
							.push(row.get(*row_index)?.clone());
						Some(())
					})
					.collect::<Option<()>>()
					.ok_or_else(|| ValidateError::UnreachableUniqueValues.into())
			})?;

		let mut new_values: Vec<Vec<Value>> = vec![vec![]; unique_columns.len()];
		rows.iter().try_for_each::<_, Result<_>>(|row| {
			unique_columns
				.iter()
				.enumerate()
				.map(|(index, row_index)| {
					new_values
						.get_mut(index)?
						.push(row.0.get(*row_index)?.clone());
					Some(())
				})
				.collect::<Option<()>>()
				.ok_or_else(|| ValidateError::UnreachableUniqueValues.into())
		})?;
		let mut existing_values_iter = existing_values.into_iter();
		new_values
			.into_iter()
			.map(|mut new_values| {
				let mut existing_values = existing_values_iter.next()?;

				existing_values.sort_unstable_by(|value_l, value_r| {
					value_l.partial_cmp(value_r).unwrap_or(Ordering::Equal)
				});
				new_values.sort_unstable_by(|value_l, value_r| {
					value_l.partial_cmp(value_r).unwrap_or(Ordering::Equal)
				});

				let mut existing_values = existing_values.into_iter();
				let mut new_values = new_values.into_iter();

				let mut new_value = some_or_continue!(new_values.next());
				let mut existing_value = some_or!(existing_values.next(), {
					loop {
						let new_new = some_or_continue!(new_values.next());
						if new_new == new_value {
							return Some(Err(ValidateError::DuplicateEntryOnUniqueField.into()));
						}
						new_value = new_new;
					}
				});

				loop {
					match existing_value.null_cmp(&new_value) {
						Some(Ordering::Equal) => {
							return Some(Err(ValidateError::DuplicateEntryOnUniqueField.into()))
						}
						Some(Ordering::Greater) => {
							let new_new = some_or_continue!(new_values.next());
							if new_new == new_value {
								return Some(
									Err(ValidateError::DuplicateEntryOnUniqueField.into()),
								);
							}
							new_value = new_new;
						}
						Some(Ordering::Less) => {
							existing_value = some_or!(existing_values.next(), {
								loop {
									let new_new = some_or_continue!(new_values.next());
									if new_new == new_value {
										return Some(Err(
											ValidateError::DuplicateEntryOnUniqueField.into(),
										));
									}
									new_value = new_new;
								}
							});
						}
						None => {
							let new_new = some_or_continue!(new_values.next());
							if new_new == new_value {
								return Some(
									Err(ValidateError::DuplicateEntryOnUniqueField.into()),
								);
							}
							new_value = new_new;
							existing_value = some_or!(existing_values.next(), {
								loop {
									let new_new = some_or_continue!(new_values.next());
									if new_new == new_value {
										return Some(Err(
											ValidateError::DuplicateEntryOnUniqueField.into(),
										));
									}
									new_value = new_new;
								}
							});
						}
					}
				}
			})
			.collect::<Option<Result<()>>>()
			.ok_or(ValidateError::UnreachableUniqueValues)?
	}
}