// SPDX-License-Identifier: GPL-3.0-or-later
use std::{
    path::PathBuf,
    str::FromStr,
    sync::{LazyLock, OnceLock},
};

use anyhow::Result;
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};

static DB_PATH: LazyLock<PathBuf> = LazyLock::new(|| gtk::glib::user_data_dir().join("decoder"));
static POOL: OnceLock<sqlx::Pool<sqlx::Sqlite>> = OnceLock::new();

pub(crate) async fn connection() -> anyhow::Result<sqlx::pool::PoolConnection<sqlx::Sqlite>> {
    let pool = if let Some(pool) = POOL.get() {
        pool.clone()
    } else {
        let pool = sqlx_pool().await?;
        POOL.set(pool.clone()).expect("Failed to set pool");
        pool
    };

    pool.acquire().await.map_err(anyhow::Error::new)
}

async fn sqlx_pool() -> Result<sqlx::Pool<sqlx::Sqlite>> {
    let db_path = &DB_PATH.join("codes.db");
    let uri = format!("file://{}", db_path.display());

    async_fs::create_dir_all(&*DB_PATH).await?;

    let opts = SqliteConnectOptions::from_str(&uri)?.create_if_missing(true);
    let pool = SqlitePoolOptions::new().connect_with(opts).await?;

    tracing::info!("Database pool initialized.");
    tracing::info!("Running DB Migrations...");
    sqlx::migrate!("./migrations").run(&pool).await?;

    Ok(pool)
}

pub async fn close_pool() {
    if let Some(pool) = POOL.get() {
        pool.close().await;
        tracing::info!("Sqlite connection successfully closed");
    }
}
