use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

/// Tracks active connections and enforces limits.
pub struct ConnectionPool {
    active: AtomicUsize,
    max: usize,
}

impl ConnectionPool {
    pub fn new(max_connections: usize) -> Self {
        Self {
            active: AtomicUsize::new(0),
            max: max_connections,
        }
    }

    /// Try to acquire a connection slot. Returns `false` if the pool is full.
    pub fn try_acquire(&self) -> bool {
        loop {
            let current = self.active.load(Ordering::Relaxed);
            if current >= self.max {
                return false;
            }
            if self
                .active
                .compare_exchange(current, current + 1, Ordering::AcqRel, Ordering::Relaxed)
                .is_ok()
            {
                return true;
            }
        }
    }

    /// Release a connection slot.
    pub fn release(&self) {
        self.active.fetch_sub(1, Ordering::AcqRel);
    }

    /// Current number of active connections.
    pub fn active_count(&self) -> usize {
        self.active.load(Ordering::Relaxed)
    }

    /// Maximum number of allowed connections.
    pub fn max_connections(&self) -> usize {
        self.max
    }
}

/// RAII guard that releases a connection slot on drop.
pub struct ConnectionGuard {
    pool: Arc<ConnectionPool>,
}

impl ConnectionGuard {
    pub fn new(pool: Arc<ConnectionPool>) -> Option<Self> {
        if pool.try_acquire() {
            Some(Self { pool })
        } else {
            None
        }
    }
}

impl Drop for ConnectionGuard {
    fn drop(&mut self) {
        self.pool.release();
    }
}
