use crate::ctx::Context;
use crate::dbs::Options;
use crate::doc::CursorDoc;
use crate::err::Error;
use crate::sql::{
	fmt::{pretty_indent, Fmt, Pretty},
	Number, Operation, Value,
};
use reblessive::tree::Stk;
use revision::revisioned;
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::fmt::{self, Display, Formatter, Write};
use std::ops;
use std::ops::Deref;
use std::ops::DerefMut;
use super::FlowResult;
pub(crate) const TOKEN: &str = "$surrealdb::private::sql::Array";
#[revisioned(revision = 1)]
#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize, Hash)]
#[serde(rename = "$surrealdb::private::sql::Array")]
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[non_exhaustive]
pub struct Array(pub Vec<Value>);
impl From<Value> for Array {
	fn from(v: Value) -> Self {
		vec![v].into()
	}
}
impl From<Vec<Value>> for Array {
	fn from(v: Vec<Value>) -> Self {
		Self(v)
	}
}
impl From<Vec<i32>> for Array {
	fn from(v: Vec<i32>) -> Self {
		Self(v.into_iter().map(Value::from).collect())
	}
}
impl From<Vec<f32>> for Array {
	fn from(v: Vec<f32>) -> Self {
		Self(v.into_iter().map(Value::from).collect())
	}
}
impl From<Vec<f64>> for Array {
	fn from(v: Vec<f64>) -> Self {
		Self(v.into_iter().map(Value::from).collect())
	}
}
impl From<Vec<usize>> for Array {
	fn from(v: Vec<usize>) -> Self {
		Self(v.into_iter().map(Value::from).collect())
	}
}
impl From<Vec<&str>> for Array {
	fn from(v: Vec<&str>) -> Self {
		Self(v.into_iter().map(Value::from).collect())
	}
}
impl From<Vec<String>> for Array {
	fn from(v: Vec<String>) -> Self {
		Self(v.into_iter().map(Value::from).collect())
	}
}
impl From<Vec<Number>> for Array {
	fn from(v: Vec<Number>) -> Self {
		Self(v.into_iter().map(Value::from).collect())
	}
}
impl From<Vec<Operation>> for Array {
	fn from(v: Vec<Operation>) -> Self {
		Self(v.into_iter().map(Value::from).collect())
	}
}
impl From<Vec<bool>> for Array {
	fn from(v: Vec<bool>) -> Self {
		Self(v.into_iter().map(Value::from).collect())
	}
}
impl From<Array> for Vec<Value> {
	fn from(s: Array) -> Self {
		s.0
	}
}
impl FromIterator<Value> for Array {
	fn from_iter<I: IntoIterator<Item = Value>>(iter: I) -> Self {
		Array(iter.into_iter().collect())
	}
}
impl Deref for Array {
	type Target = Vec<Value>;
	fn deref(&self) -> &Self::Target {
		&self.0
	}
}
impl DerefMut for Array {
	fn deref_mut(&mut self) -> &mut Self::Target {
		&mut self.0
	}
}
impl IntoIterator for Array {
	type Item = Value;
	type IntoIter = std::vec::IntoIter<Self::Item>;
	fn into_iter(self) -> Self::IntoIter {
		self.0.into_iter()
	}
}
impl Array {
		pub fn new() -> Self {
		Self::default()
	}
		pub fn with_capacity(len: usize) -> Self {
		Self(Vec::with_capacity(len))
	}
		pub fn len(&self) -> usize {
		self.0.len()
	}
		pub fn is_empty(&self) -> bool {
		self.0.is_empty()
	}
}
impl Array {
		pub(crate) async fn compute(
		&self,
		stk: &mut Stk,
		ctx: &Context,
		opt: &Options,
		doc: Option<&CursorDoc>,
	) -> FlowResult<Value> {
		let mut x = Self::with_capacity(self.len());
		for v in self.iter() {
			let v = v.compute(stk, ctx, opt, doc).await?;
			x.push(v);
		}
		Ok(Value::Array(x))
	}
	pub(crate) fn is_all_none_or_null(&self) -> bool {
		self.0.iter().all(|v| v.is_none_or_null())
	}
		pub(crate) fn is_static(&self) -> bool {
		self.iter().all(Value::is_static)
	}
		pub fn validate_computed(&self) -> Result<(), Error> {
		self.iter().try_for_each(|v| v.validate_computed())
	}
}
impl Display for Array {
	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
		let mut f = Pretty::from(f);
		f.write_char('[')?;
		if !self.is_empty() {
			let indent = pretty_indent();
			write!(f, "{}", Fmt::pretty_comma_separated(self.as_slice()))?;
			drop(indent);
		}
		f.write_char(']')
	}
}
impl ops::Add<Value> for Array {
	type Output = Self;
	fn add(mut self, other: Value) -> Self {
		self.0.push(other);
		self
	}
}
impl ops::Add for Array {
	type Output = Self;
	fn add(mut self, mut other: Self) -> Self {
		self.0.append(&mut other.0);
		self
	}
}
impl ops::Sub<Value> for Array {
	type Output = Self;
	fn sub(mut self, other: Value) -> Self {
		if let Some(p) = self.0.iter().position(|x| *x == other) {
			self.0.remove(p);
		}
		self
	}
}
impl ops::Sub for Array {
	type Output = Self;
	fn sub(mut self, other: Self) -> Self {
		for v in other.0 {
			if let Some(p) = self.0.iter().position(|x| *x == v) {
				self.0.remove(p);
			}
		}
		self
	}
}
pub trait Abolish<T> {
	fn abolish<F>(&mut self, f: F)
	where
		F: FnMut(usize) -> bool;
}
impl<T> Abolish<T> for Vec<T> {
	fn abolish<F>(&mut self, mut f: F)
	where
		F: FnMut(usize) -> bool,
	{
		let mut i = 0;
						self.retain(|_| {
			let retain = !f(i);
			i += 1;
			retain
		});
	}
}
pub(crate) trait Clump<T> {
	fn clump(self, clump_size: usize) -> Result<T, Error>;
}
impl Clump<Array> for Array {
	fn clump(self, clump_size: usize) -> Result<Array, Error> {
		if clump_size < 1 {
			return Err(Error::InvalidArguments {
				name: "array::clump".to_string(),
				message: "The second argument must be an integer greater than 0".to_string(),
			});
		}
		Ok(self
			.0
			.chunks(clump_size)
			.map::<Value, _>(|chunk| chunk.to_vec().into())
			.collect::<Vec<_>>()
			.into())
	}
}
pub(crate) trait Combine<T> {
	fn combine(self, other: T) -> T;
}
impl Combine<Array> for Array {
	fn combine(self, other: Self) -> Array {
		let mut out = Self::with_capacity(self.len().saturating_mul(other.len()));
		for a in self.iter() {
			for b in other.iter() {
				out.push(vec![a.clone(), b.clone()].into());
			}
		}
		out
	}
}
pub(crate) trait Complement<T> {
	fn complement(self, other: T) -> T;
}
impl Complement<Array> for Array {
	fn complement(self, other: Self) -> Array {
		let mut out = Array::new();
		for v in self.into_iter() {
			if !other.contains(&v) {
				out.push(v)
			}
		}
		out
	}
}
pub(crate) trait Difference<T> {
	fn difference(self, other: T) -> T;
}
impl Difference<Array> for Array {
	fn difference(self, mut other: Array) -> Array {
		let mut out = Array::new();
		for v in self.into_iter() {
			if let Some(pos) = other.iter().position(|w| v == *w) {
				other.remove(pos);
			} else {
				out.push(v);
			}
		}
		out.append(&mut other);
		out
	}
}
pub(crate) trait Flatten<T> {
	fn flatten(self) -> T;
}
impl Flatten<Array> for Array {
	fn flatten(self) -> Array {
		let mut out = Array::new();
		for v in self.into_iter() {
			match v {
				Value::Array(mut a) => out.append(&mut a),
				_ => out.push(v),
			}
		}
		out
	}
}
pub(crate) trait Intersect<T> {
	fn intersect(self, other: T) -> T;
}
impl Intersect<Self> for Array {
	fn intersect(self, mut other: Self) -> Self {
		let mut out = Self::new();
		for v in self.0.into_iter() {
			if let Some(pos) = other.iter().position(|w| v == *w) {
				other.remove(pos);
				out.push(v);
			}
		}
		out
	}
}
pub(crate) trait Matches<T> {
							fn matches(self, compare_val: Value) -> T;
}
impl Matches<Array> for Array {
	fn matches(self, compare_val: Value) -> Array {
		self.iter().map(|arr_val| (arr_val == &compare_val).into()).collect::<Vec<Value>>().into()
	}
}
pub(crate) trait Transpose<T> {
																																fn transpose(self) -> T;
}
impl Transpose<Array> for Array {
	fn transpose(self) -> Array {
		if self.is_empty() {
			return self;
		}
						let mut transposed_vec = Vec::<Value>::with_capacity(self.len());
		let mut iters = self
			.iter()
			.map(|v| {
				if let Value::Array(arr) = v {
					Box::new(arr.iter().cloned()) as Box<dyn ExactSizeIterator<Item = Value>>
				} else {
					Box::new(std::iter::once(v).cloned())
						as Box<dyn ExactSizeIterator<Item = Value>>
				}
			})
			.collect::<Vec<_>>();
						let longest_length = iters.iter().map(|i| i.len()).max().unwrap();
		for _ in 0..longest_length {
			transposed_vec.push(
				iters
					.iter_mut()
					.map(|i| i.next().unwrap_or(Value::None))
					.collect::<Vec<_>>()
					.into(),
			);
		}
		transposed_vec.into()
	}
}
pub(crate) trait Union<T> {
	fn union(self, other: T) -> T;
}
impl Union<Self> for Array {
	fn union(mut self, mut other: Self) -> Array {
		self.append(&mut other);
		self.uniq()
	}
}
pub(crate) trait Uniq<T> {
	fn uniq(self) -> T;
}
impl Uniq<Array> for Array {
	fn uniq(mut self) -> Array {
		#[allow(clippy::mutable_key_type)]
		let mut set: HashSet<&Value> = HashSet::new();
		let mut to_remove: Vec<usize> = Vec::new();
		for (i, item) in self.iter().enumerate() {
			if !set.insert(item) {
				to_remove.push(i);
			}
		}
		for i in to_remove.iter().rev() {
			self.remove(*i);
		}
		self
	}
}
pub(crate) trait Windows<T> {
	fn windows(self, window_size: usize) -> Result<T, Error>;
}
impl Windows<Array> for Array {
	fn windows(self, window_size: usize) -> Result<Array, Error> {
		if window_size < 1 {
			return Err(Error::InvalidArguments {
				name: "array::windows".to_string(),
				message: "The second argument must be an integer greater than 0".to_string(),
			});
		}
		Ok(self
			.0
			.windows(window_size)
			.map::<Value, _>(|chunk| chunk.to_vec().into())
			.collect::<Vec<_>>()
			.into())
	}
}