mod config;
mod db;

use sqlx::Executor;

pub use crate::config::Config as DbConfig;
pub use crate::db::DB;

pub async fn ensure(app_name: &str, cfgs: &[&DbConfig]) -> anyhow::Result<()> {
    for cfg in cfgs {
        let db = DB::new_root(app_name, cfg).await?;
        let query_args = ::core::result::Result::<_, ::sqlx::error::BoxDynError>::Ok(
            <sqlx::postgres::Postgres as ::sqlx::database::Database>::Arguments::<'_>::default(),
        );
        let databases: Vec<String> =
            sqlx::__query_with_result("SELECT datname FROM pg_database;", query_args)
                .try_map(|v: sqlx::postgres::PgRow| {
                    use ::sqlx::Row as _;
                    v.try_get_unchecked::<String, _>(0usize)
                })
                .fetch_all(db.pool())
                .await?;

        if let Some(database) = cfg.database() {
            if !databases.iter().any(|datname| datname == database) {
                db.pool()
                    .execute(format!("CREATE DATABASE {database}").as_str())
                    .await?;
            }
        }

        if let Some((username, password)) = cfg.username().zip(cfg.password()) {
            let query_args = ::core::result::Result::<_, ::sqlx::error::BoxDynError>::Ok(
                <sqlx::postgres::Postgres as ::sqlx::database::Database>::Arguments::<'_>::default(
                ),
            );
            let users: Vec<Option<String>> =
                sqlx::__query_with_result("SELECT usename FROM pg_catalog.pg_user;", query_args)
                    .try_map(|v: sqlx::postgres::PgRow| {
                        use ::sqlx::Row as _;
                        v.try_get_unchecked::<Option<String>, _>(0usize)
                    })
                    .fetch_all(db.pool())
                    .await?;
            if !users
                .iter()
                .any(|usename| usename.as_deref() == Some(username))
            {
                db.pool()
                    .execute(
                        format!("CREATE USER {username} WITH SUPERUSER PASSWORD '{password}'")
                            .as_str(),
                    )
                    .await?;
            }
        }
    }
    Ok(())
}
