#![cfg(any(feature = "db-mysql", feature = "db-postgres"))]

use std::time::{SystemTime, UNIX_EPOCH};

#[cfg(feature = "db-mysql")]
use rs_zero::db::{DatabaseConfig, connect_mysql_pool, health_check_mysql};
#[cfg(feature = "db-postgres")]
use rs_zero::db::{DatabaseConfig, connect_postgres_pool, health_check_postgres};

#[cfg(feature = "db-mysql")]
#[tokio::test]
#[ignore = "requires RS_ZERO_MYSQL_URL pointing to a running MySQL instance"]
async fn mysql_external_pool_lifecycle() {
    let url = std::env::var("RS_ZERO_MYSQL_URL")
        .unwrap_or_else(|_| "mysql://rs_zero:rs_zero@127.0.0.1:3306/rs_zero".to_string());
    let pool = connect_mysql_pool(&DatabaseConfig::mysql(url))
        .await
        .expect("connect mysql");

    health_check_mysql(&pool).await.expect("mysql health");
    let table = format!("rs_zero_mysql_{}", unique_suffix());
    let create =
        format!("CREATE TABLE `{table}` (`id` BIGINT PRIMARY KEY, `name` VARCHAR(64) NOT NULL)");
    let insert = format!("INSERT INTO `{table}` (`id`, `name`) VALUES (?, ?)");
    let select = format!("SELECT `name` FROM `{table}` WHERE `id` = ?");
    let drop = format!("DROP TABLE IF EXISTS `{table}`");

    sqlx::query(&create).execute(&pool).await.expect("create");
    sqlx::query(&insert)
        .bind(1_i64)
        .bind("ready")
        .execute(&pool)
        .await
        .expect("insert");
    let name: String = sqlx::query_scalar(&select)
        .bind(1_i64)
        .fetch_one(&pool)
        .await
        .expect("select");
    assert_eq!(name, "ready");
    sqlx::query(&drop).execute(&pool).await.expect("drop");
}

#[cfg(feature = "db-postgres")]
#[tokio::test]
#[ignore = "requires RS_ZERO_POSTGRES_URL pointing to a running PostgreSQL instance"]
async fn postgres_external_pool_lifecycle() {
    let url = std::env::var("RS_ZERO_POSTGRES_URL")
        .unwrap_or_else(|_| "postgres://rs_zero:rs_zero@127.0.0.1:5432/rs_zero".to_string());
    let pool = connect_postgres_pool(&DatabaseConfig::postgres(url))
        .await
        .expect("connect postgres");

    health_check_postgres(&pool).await.expect("postgres health");
    let table = format!("rs_zero_postgres_{}", unique_suffix());
    let create = format!("CREATE TABLE {table} (id BIGINT PRIMARY KEY, name TEXT NOT NULL)");
    let insert = format!("INSERT INTO {table} (id, name) VALUES ($1, $2)");
    let select = format!("SELECT name FROM {table} WHERE id = $1");
    let drop = format!("DROP TABLE IF EXISTS {table}");

    sqlx::query(&create).execute(&pool).await.expect("create");
    let mut transaction = pool.begin().await.expect("begin");
    sqlx::query(&insert)
        .bind(1_i64)
        .bind("ready")
        .execute(&mut *transaction)
        .await
        .expect("insert");
    transaction.commit().await.expect("commit");
    let name: String = sqlx::query_scalar(&select)
        .bind(1_i64)
        .fetch_one(&pool)
        .await
        .expect("select");
    assert_eq!(name, "ready");
    sqlx::query(&drop).execute(&pool).await.expect("drop");
}

fn unique_suffix() -> String {
    let nanos = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap_or_default()
        .as_nanos();
    format!("{nanos}_{}", std::process::id())
}
