use self::query::ValidQuery;
use crate::api::opt;
use crate::api::opt::auth;
use crate::api::opt::auth::Credentials;
use crate::api::opt::auth::Jwt;
use crate::api::opt::IntoEndpoint;
use crate::api::Connect;
use crate::api::Connection;
use crate::api::OnceLockExt;
use crate::api::Surreal;
use crate::opt::IntoExportDestination;
use crate::opt::WaitFor;
use serde::Serialize;
use std::borrow::Cow;
use std::marker::PhantomData;
use std::path::Path;
use std::pin::Pin;
use std::sync::Arc;
use std::sync::OnceLock;
use std::time::Duration;
use surrealdb_core::sql::to_value as to_core_value;
pub(crate) mod live;
pub(crate) mod query;
mod authenticate;
mod begin;
mod cancel;
mod commit;
mod content;
mod create;
mod delete;
mod export;
mod health;
mod import;
mod insert;
mod insert_relation;
mod invalidate;
mod merge;
mod patch;
mod run;
mod select;
mod set;
mod signin;
mod signup;
mod unset;
mod update;
mod upsert;
mod use_db;
mod use_ns;
mod version;
#[cfg(test)]
mod tests;
pub use authenticate::Authenticate;
#[doc(hidden)]
pub use begin::Begin;
#[doc(hidden)]
pub use begin::Transaction;
#[doc(hidden)]
pub use cancel::Cancel;
#[doc(hidden)]
pub use commit::Commit;
pub use content::Content;
pub use create::Create;
pub use delete::Delete;
pub use export::{Backup, Export};
use futures::Future;
pub use health::Health;
pub use import::Import;
pub use insert::Insert;
pub use invalidate::Invalidate;
pub use live::Stream;
pub use merge::Merge;
pub use patch::Patch;
pub use query::Query;
pub use query::QueryStream;
pub use run::IntoFn;
pub use run::Run;
pub use select::Select;
use serde_content::Serializer;
pub use set::Set;
pub use signin::Signin;
pub use signup::Signup;
use tokio::sync::watch;
pub use unset::Unset;
pub use update::Update;
pub use upsert::Upsert;
pub use use_db::UseDb;
pub use use_ns::UseNs;
pub use version::Version;
use super::opt::CreateResource;
use super::opt::IntoResource;
pub(crate) type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + Sync + 'a>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
pub struct Stats {
		pub execution_time: Option<Duration>,
}
pub struct Model;
pub struct ExportConfig;
pub struct Live;
#[derive(Debug)]
pub struct WithStats<T>(pub T);
impl<C> Surreal<C>
where
	C: Connection,
{
																																																																																													pub fn init() -> Self {
		Self {
			router: Arc::new(OnceLock::new()),
			waiter: Arc::new(watch::channel(None)),
			engine: PhantomData,
		}
	}
																				pub fn new<P>(address: impl IntoEndpoint<P, Client = C>) -> Connect<C, Self> {
		Connect {
			router: Arc::new(OnceLock::new()),
			engine: PhantomData,
			address: address.into_endpoint(),
			capacity: 0,
			waiter: Arc::new(watch::channel(None)),
			response_type: PhantomData,
		}
	}
		#[doc(hidden)]
	#[cfg(surrealdb_unstable)] 	pub fn transaction(self) -> Begin<C> {
		warn!("Client side transactions are not yet supported. This API doesn't do anything yet.");
		Begin {
			client: self,
		}
	}
													pub fn use_ns(&self, ns: impl Into<String>) -> UseNs<C> {
		UseNs {
			client: Cow::Borrowed(self),
			ns: ns.into(),
		}
	}
													pub fn use_db(&self, db: impl Into<String>) -> UseDb<C> {
		UseDb {
			client: Cow::Borrowed(self),
			ns: None,
			db: db.into(),
		}
	}
																																	pub fn set(&self, key: impl Into<String>, value: impl Serialize + 'static) -> Set<C> {
		Set {
			client: Cow::Borrowed(self),
			key: key.into(),
			value: to_core_value(value).map_err(Into::into),
		}
	}
																																	pub fn unset(&self, key: impl Into<String>) -> Unset<C> {
		Unset {
			client: Cow::Borrowed(self),
			key: key.into(),
		}
	}
																																																				pub fn signup<R>(&self, credentials: impl Credentials<auth::Signup, R>) -> Signup<C, R> {
		Signup {
			client: Cow::Borrowed(self),
			credentials: Serializer::new().serialize(credentials),
			response_type: PhantomData,
		}
	}
																																																																																																														pub fn signin<R>(&self, credentials: impl Credentials<auth::Signin, R>) -> Signin<C, R> {
		Signin {
			client: Cow::Borrowed(self),
			credentials: Serializer::new().serialize(credentials),
			response_type: PhantomData,
		}
	}
													pub fn invalidate(&self) -> Invalidate<C> {
		Invalidate {
			client: Cow::Borrowed(self),
		}
	}
														pub fn authenticate(&self, token: impl Into<Jwt>) -> Authenticate<C> {
		Authenticate {
			client: Cow::Borrowed(self),
			token: token.into(),
		}
	}
																																																		pub fn query(&self, query: impl opt::IntoQuery) -> Query<C> {
		let inner = query.into_query().map(|x| ValidQuery {
			client: Cow::Borrowed(self),
			query: x,
			bindings: Default::default(),
			register_live_queries: true,
		});
		Query {
			inner,
		}
	}
																																								pub fn select<O>(&self, resource: impl IntoResource<O>) -> Select<C, O> {
		Select {
			client: Cow::Borrowed(self),
			resource: resource.into_resource(),
			response_type: PhantomData,
			query_type: PhantomData,
		}
	}
																																															pub fn create<R>(&self, resource: impl CreateResource<R>) -> Create<C, R> {
		Create {
			client: Cow::Borrowed(self),
			resource: resource.into_resource(),
			response_type: PhantomData,
		}
	}
																																																																																																																																										pub fn insert<O>(&self, resource: impl IntoResource<O>) -> Insert<C, O> {
		Insert {
			client: Cow::Borrowed(self),
			resource: resource.into_resource(),
			response_type: PhantomData,
		}
	}
																																																																																																																																																							pub fn upsert<O>(&self, resource: impl IntoResource<O>) -> Upsert<C, O> {
		Upsert {
			client: Cow::Borrowed(self),
			resource: resource.into_resource(),
			response_type: PhantomData,
		}
	}
																																																																																																																																																							pub fn update<O>(&self, resource: impl IntoResource<O>) -> Update<C, O> {
		Update {
			client: Cow::Borrowed(self),
			resource: resource.into_resource(),
			response_type: PhantomData,
		}
	}
																									pub fn delete<O>(&self, resource: impl IntoResource<O>) -> Delete<C, O> {
		Delete {
			client: Cow::Borrowed(self),
			resource: resource.into_resource(),
			response_type: PhantomData,
		}
	}
													pub fn version(&self) -> Version<C> {
		Version {
			client: Cow::Borrowed(self),
		}
	}
																						pub fn run<R>(&self, function: impl IntoFn) -> Run<C, R> {
		Run {
			client: Cow::Borrowed(self),
			function: function.into_fn(),
			args: Ok(serde_content::Value::Tuple(vec![])),
			response_type: PhantomData,
		}
	}
													pub fn health(&self) -> Health<C> {
		Health {
			client: Cow::Borrowed(self),
		}
	}
		pub async fn wait_for(&self, event: WaitFor) {
		let mut rx = self.waiter.0.subscribe();
		rx.wait_for(|current| match current {
						None => false,
						Some(WaitFor::Connection) => matches!(event, WaitFor::Connection),
						Some(WaitFor::Database) => matches!(event, WaitFor::Connection | WaitFor::Database),
		})
		.await
		.ok();
	}
																																			pub fn export<R>(&self, target: impl IntoExportDestination<R>) -> Export<C, R> {
		Export {
			client: Cow::Borrowed(self),
			target: target.into_export_destination(),
			ml_config: None,
			db_config: None,
			response: PhantomData,
			export_type: PhantomData,
		}
	}
																				pub fn import<P>(&self, file: P) -> Import<C>
	where
		P: AsRef<Path>,
	{
		Import {
			client: Cow::Borrowed(self),
			file: file.as_ref().to_owned(),
			is_ml: false,
			import_type: PhantomData,
		}
	}
}