//! Factory-layer implementation for [`ConnectionPoolManager`].
//!
//! The manager holds shared pool defaults and builds [`PgPoolOptions`] /
//! produces live [`ConnectionPool`]s from a URI. It carries no runtime state;
//! cloning it is cheap and deliberate so the same defaults can be handed to
//! multiple connect sites.

use sqlx::postgres::PgPoolOptions;
use std::time::Duration;

use crate::client::config::PoolConfig;
use crate::features::connection_pooler::{ConnectionPool, ConnectionPoolManager};

impl Default for ConnectionPoolManager {
    /// Default manager: default [`PoolConfig`], 30 minute max lifetime,
    /// `test_before_acquire` disabled.
    fn default() -> Self {
        Self {
            config: PoolConfig::default(),
            max_lifetime: Duration::from_secs(1800),
            test_before_acquire: false,
        }
    }
}

impl ConnectionPoolManager {
    /// Construct a manager from an explicit [`PoolConfig`], keeping other
    /// defaults (`max_lifetime`, `test_before_acquire`).
    pub fn new(config: PoolConfig) -> Self {
        Self {
            config,
            ..Default::default()
        }
    }

    /// Override the max lifetime applied to pools produced by this manager.
    pub fn with_max_lifetime(mut self, max_lifetime: Duration) -> Self {
        self.max_lifetime = max_lifetime;
        self
    }

    /// Enable or disable validating a pooled connection before handing it out.
    pub fn with_test_before_acquire(mut self, test_before_acquire: bool) -> Self {
        self.test_before_acquire = test_before_acquire;
        self
    }

    /// Build [`PgPoolOptions`] with the manager's configured defaults.
    ///
    /// Exposed so callers that need raw sqlx options (e.g. customizing further
    /// before connecting) can reuse the shared limits.
    pub fn build_options(&self) -> PgPoolOptions {
        PgPoolOptions::new()
            .max_connections(self.config.max_connections)
            .min_connections(self.config.min_connections)
            .acquire_timeout(self.config.connection_timeout)
            .idle_timeout(Some(self.config.idle_timeout))
            .max_lifetime(Some(self.max_lifetime))
            .test_before_acquire(self.test_before_acquire)
    }

    /// Open a live [`ConnectionPool`] for `client_name` against `uri`.
    ///
    /// This is the canonical "create" entry point: the factory owns
    /// construction end-to-end and returns the owning wrapper, not a raw
    /// [`sqlx::postgres::PgPool`].
    pub async fn open(
        &self,
        client_name: String,
        uri: &str,
    ) -> Result<ConnectionPool, sqlx::Error> {
        let pool = self.build_options().connect(uri).await?;
        Ok(ConnectionPool::wrap(client_name, pool, self.clone()))
    }
}
