use sqlx::PgPool;

use crate::error::Result;
use crate::repositories::{
    PgAddressRepository, PgApiKeyRepository, PgAuditLogRepository, PgCountryRepository,
};

/// Holds all Postgres-backed repositories. Analogous to cedros-login's `Storage`.
#[derive(Clone)]
pub struct Storage {
    pub address_repo: PgAddressRepository,
    pub api_key_repo: PgApiKeyRepository,
    pub audit_log_repo: PgAuditLogRepository,
    pub country_repo: PgCountryRepository,
    pool: PgPool,
}

impl Storage {
    pub async fn from_database_url(url: &str) -> Result<Self> {
        let pool = PgPool::connect(url).await?;
        Ok(Self::from_pool(pool))
    }

    pub fn from_pool(pool: PgPool) -> Self {
        Self {
            address_repo: PgAddressRepository::new(pool.clone()),
            api_key_repo: PgApiKeyRepository::new(pool.clone()),
            audit_log_repo: PgAuditLogRepository::new(pool.clone()),
            country_repo: PgCountryRepository::new(pool.clone()),
            pool,
        }
    }

    /// Run database migrations.
    pub async fn migrate(&self) -> Result<()> {
        sqlx::migrate!("./migrations")
            .run(&self.pool)
            .await?;
        Ok(())
    }
}
