use std::ops::DerefMut;

use sqlx::pool::PoolConnection;
use sqlx::Sqlite;

use crate::db::errors::DatabaseError;
use crate::db::models::*;

pub async fn create_tag(
	conn: &mut PoolConnection<Sqlite>,
	new_tag: &str,
) -> Result<Tag, DatabaseError> {
	sqlx::query_as!(
		Tag,
		"INSERT INTO tags (tag) VALUES (?) RETURNING *",
		new_tag
	)
	.fetch_optional(conn.deref_mut())
	.await?
	.ok_or(DatabaseError::InsertGetError)
}

pub async fn get_tag(
	conn: &mut PoolConnection<Sqlite>,
	target_tag: &str,
) -> Result<Tag, DatabaseError> {
	sqlx::query_as!(Tag, "SELECT * FROM tags WHERE tag = ?", target_tag)
		.fetch_optional(conn.deref_mut())
		.await
		.map(|t| t.ok_or(DatabaseError::NotFound))?
}

#[allow(dead_code)]
pub async fn create_junction_tag_relay(
	conn: &mut PoolConnection<Sqlite>,
	target_tag: Tag,
	target_relay: &Relay,
) -> Result<JunctionTag, DatabaseError> {
	sqlx::query_as!(
		JunctionTag,
		"INSERT INTO junction_tag (tag_id, relay_id) VALUES (?, ?) RETURNING *",
		target_tag.id,
		target_relay.id
	)
	.fetch_optional(conn.deref_mut())
	.await?
	.ok_or(DatabaseError::InsertGetError)
}

pub async fn create_junction_tag_schedule(
	conn: &mut PoolConnection<Sqlite>,
	target_tag: Tag,
	target_schedule: &Schedule,
) -> Result<JunctionTag, DatabaseError> {
	sqlx::query_as!(
		JunctionTag,
		"INSERT INTO junction_tag (tag_id, schedule_id) VALUES (?, ?) RETURNING *",
		target_tag.id,
		target_schedule.id
	)
	.fetch_optional(conn.deref_mut())
	.await?
	.ok_or(DatabaseError::InsertGetError)
}