// tests/common/mod.rs

use dotenvy::dotenv;
use rand::distr::Alphanumeric;
use rand::Rng;
use sqlx::{postgres::PgPoolOptions, Connection, Executor, PgConnection, PgPool};
use std::env;

fn get_database_url() -> String {
    dotenv().ok();
    env::var("TEST_DATABASE_URL").expect("TEST_DATABASE_URL must be set")
}

async fn get_root_connection() -> PgConnection {
    PgConnection::connect(&get_database_url())
        .await
        .expect("Failed to create root connection to test database")
}

/// The primary test setup function.
/// Creates a new, unique schema and returns a connection pool that is scoped to that schema.
/// This is the key to test isolation.
pub async fn setup_isolated_db() -> PgPool {
    let mut root_conn = get_root_connection().await;

    // Make schema names more unique - include timestamp + random
    let schema_name = format!(
        "test_{}_{}",
        std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .unwrap()
            .as_nanos(),
        rand::rng()
            .sample_iter(&Alphanumeric)
            .take(8)
            .map(char::from)
            .collect::<String>()
            .to_lowercase()
    );

    root_conn
        .execute(format!("CREATE SCHEMA \"{}\"", schema_name).as_str())
        .await
        .unwrap_or_else(|_| panic!("Failed to create schema: {}", schema_name));

    root_conn
        .execute("CREATE SCHEMA IF NOT EXISTS \"default\"")
        .await
        .unwrap();

    let pool = PgPoolOptions::new()
        .max_connections(5)
        .after_connect(move |conn, _meta| {
            let schema_name = schema_name.clone();
            Box::pin(async move {
                conn.execute(format!("SET search_path TO \"{}\", \"default\", \"public\"", schema_name).as_str())
                    .await?;
                Ok(())
            })
        })
        .connect(&get_database_url())
        .await
        .expect("Failed to create isolated pool");

    sqlx::migrate!()
        .run(&pool)
        .await
        .expect("Migrations failed in isolated schema");

    sqlx::query!(
        r#"
        INSERT INTO schemas (name)
        VALUES ('default')
        ON CONFLICT (name) DO NOTHING
        "#
    )
    .execute(&pool)
    .await
    .expect("Failed to insert test profile in isolated schema");

    pool
}

/// Compatibility alias for the old function name
/// This allows existing tests to continue working without modification
pub async fn setup_test_db() -> PgPool {
    setup_isolated_db().await
}
