use std::str::FromStr;

use sqlx::migrate::Migrator;
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
use sqlx::{ConnectOptions, Pool, Sqlite};

mod controllers;
mod junction_relay_schedule;
mod junction_tag;
mod r#macro;
mod macro_action;
mod model_utils;
mod relays;
mod schedules;
mod tag;

pub use controllers::DbController;
pub use junction_relay_schedule::DbJunctionRelaySchedule;
pub use junction_tag::DbJunctionTag;
pub use macro_action::DbMacroAction;
pub use r#macro::DbMacro;
pub use relays::DbRelay;
pub use schedules::{DbPeriods, DbSchedule};
pub use tag::DbTag;

use crate::errors::{DatabaseError, EmgauwaError};

static MIGRATOR: Migrator = sqlx::migrate!("../migrations"); // defaults to "./migrations"

pub async fn run_migrations(pool: &Pool<Sqlite>) -> Result<(), EmgauwaError> {
	log::info!("Running migrations");
	MIGRATOR.run(pool).await.map_err(DatabaseError::from)?;
	Ok(())
}

pub async fn init(db: &str) -> Result<Pool<Sqlite>, EmgauwaError> {
	let options = SqliteConnectOptions::from_str(db)?
		.create_if_missing(true)
		.log_statements(log::LevelFilter::Trace);

	let pool: Pool<Sqlite> = SqlitePoolOptions::new()
		.acquire_timeout(std::time::Duration::from_secs(1))
		.max_connections(5)
		.connect_with(options)
		.await?;

	run_migrations(&pool).await?;

	let mut pool_conn = pool.acquire().await?;

	DbSchedule::get_on(&mut pool_conn).await?;
	DbSchedule::get_off(&mut pool_conn).await?;

	Ok(pool)
}