mod controller;
mod r#macro;
mod macro_action;
mod relay;
mod schedule;
mod tag;

pub use controller::Controller;
pub use macro_action::MacroAction;
pub use r#macro::Macro;
pub use relay::Relay;
pub use schedule::Schedule;
use sqlx::pool::PoolConnection;
use sqlx::Sqlite;
pub use tag::Tag;

use crate::errors::DatabaseError;

pub trait FromDbModel {
	type DbModel: Clone;
	type DbModelCache: Clone;

	fn from_db_model(
		conn: &mut PoolConnection<Sqlite>,
		db_model: Self::DbModel,
	) -> Result<Self, DatabaseError>
	where
		Self: Sized;

	fn from_db_model_cache(
		conn: &mut PoolConnection<Sqlite>,
		db_model: Self::DbModel,
		cache: Self::DbModelCache,
	) -> Result<Self, DatabaseError>
	where
		Self: Sized;
}

fn convert_db_list_generic<T: FromDbModel>(
	conn: &mut PoolConnection<Sqlite>,
	db_models: Vec<T::DbModel>,
	cache: Option<T::DbModelCache>,
) -> Result<Vec<T>, DatabaseError> {
	let mut result: Vec<T> = Vec::new();
	for db_model in db_models {
		let new = match &cache {
			Some(c) => T::from_db_model_cache(conn, db_model, c.clone()),
			None => T::from_db_model(conn, db_model),
		}?;
		result.push(new);
	}
	Ok(result)
}

pub fn convert_db_list<T: FromDbModel>(
	conn: &mut PoolConnection<Sqlite>,
	db_models: Vec<T::DbModel>,
) -> Result<Vec<T>, DatabaseError> {
	convert_db_list_generic(conn, db_models, None)
}

pub fn convert_db_list_cache<T: FromDbModel>(
	conn: &mut PoolConnection<Sqlite>,
	db_models: Vec<T::DbModel>,
	cache: T::DbModelCache,
) -> Result<Vec<T>, DatabaseError> {
	convert_db_list_generic(conn, db_models, Some(cache))
}