use uuid::Uuid;

use crate::db::schema::User;

use super::schema::{DbHook, DollTagsDb, TrxHook};

pub async fn get(mut db: DollTagsDb, username: &str) -> sqlx::Result<Option<User>> {
	sqlx::query_as!(User, "select * from users where username = $1", username)
		.fetch_optional(&mut **db)
		.await
}

pub async fn get_by_id(mut db: DollTagsDb, id: &Uuid) -> sqlx::Result<Option<User>> {
	sqlx::query_as!(User, "select * from users where id = $1", id)
		.fetch_optional(&mut **db)
		.await
}

pub async fn create(
	mut db: DollTagsDb,
	username: &str,
	hashed_password: &str,
	email: Option<&str>,
) -> sqlx::Result<Uuid> {
	sqlx::query_scalar!(
		"insert into users (username, password, email) values ($1, $2, $3) returning id",
		username,
		hashed_password,
		email,
	)
	.fetch_one(&mut **db)
	.await
}

pub async fn exists(db: &mut DbHook, username: &str) -> sqlx::Result<bool> {
	Ok(
		sqlx::query_scalar!("select id from users where username = $1", username)
			.fetch_optional(&mut **db)
			.await?
			.is_some(),
	)
}

pub async fn update_info(
	db: &mut DbHook,
	id: &Uuid,
	username: &str,
	email: Option<&str>,
) -> sqlx::Result<()> {
	sqlx::query!(
		"update users set username = $1, email = $2 where id = $3",
		username,
		email,
		id
	)
	.execute(&mut **db)
	.await?;
	Ok(())
}

pub async fn update_password(db: &mut DbHook, id: &Uuid, password: &str) -> sqlx::Result<()> {
	sqlx::query!("update users set password = $1 where id = $2", password, id)
		.execute(&mut **db)
		.await?;
	Ok(())
}

pub async fn delete(trx: &mut TrxHook<'_>, id: &Uuid) -> sqlx::Result<()> {
	sqlx::query!("delete from users where id = $1", id)
		.execute(&mut **trx)
		.await?;

	Ok(())
}
