//! Pool Statistics Tracking
//!
//! Tracks connection pool metrics for monitoring and observability.

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

use serde::{Deserialize, Serialize};

/// Pool statistics snapshot
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct PoolStatistics {
    /// Total connections created
    pub total_created: usize,
    /// Currently active connections
    pub active_connections: usize,
    /// Idle connections
    pub idle_connections: usize,
    /// Total commands executed
    pub commands_executed: usize,
    /// Commands that failed
    pub commands_failed: usize,
    /// Total connection reuses
    pub total_reuses: usize,
    /// Per-host statistics
    pub per_host: HashMap<String, HostStatistics>,
}

impl PoolStatistics {
    /// Create a new statistics tracker
    pub fn new() -> Self {
        Self::default()
    }

    /// Get a snapshot of current statistics
    pub fn snapshot(&self) -> Self {
        self.clone()
    }

    /// Get success rate as percentage
    pub fn success_rate(&self) -> f64 {
        let total = self.commands_executed;
        if total == 0 {
            100.0
        } else {
            ((total - self.commands_failed) as f64 / total as f64) * 100.0
        }
    }
}

/// Per-host pool statistics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HostStatistics {
    /// Hostname
    pub host: String,
    /// Active connections for this host
    pub active_connections: usize,
    /// Idle connections for this host
    pub idle_connections: usize,
    /// Commands executed on this host
    pub commands_executed: usize,
    /// Commands failed on this host
    pub commands_failed: usize,
    /// Connection reuses for this host
    pub total_reuses: usize,
    /// Average response time in ms
    pub avg_response_time_ms: f64,
}

impl HostStatistics {
    /// Get success rate for this host
    pub fn success_rate(&self) -> f64 {
        let total = self.commands_executed;
        if total == 0 {
            100.0
        } else {
            ((total - self.commands_failed) as f64 / total as f64) * 100.0
        }
    }
}

/// Thread-safe statistics collector (used internally)
#[derive(Debug)]
pub struct StatsCollector {
    total_created: Arc<AtomicUsize>,
    commands_executed: Arc<AtomicUsize>,
    commands_failed: Arc<AtomicUsize>,
}

impl StatsCollector {
    /// Create a new statistics collector
    pub fn new() -> Self {
        Self {
            total_created: Arc::new(AtomicUsize::new(0)),
            commands_executed: Arc::new(AtomicUsize::new(0)),
            commands_failed: Arc::new(AtomicUsize::new(0)),
        }
    }

    /// Increment created connections count
    pub fn inc_created(&self) {
        self.total_created.fetch_add(1, Ordering::Relaxed);
    }

    /// Increment executed commands count
    pub fn inc_executed(&self) {
        self.commands_executed.fetch_add(1, Ordering::Relaxed);
    }

    /// Increment failed commands count
    pub fn inc_failed(&self) {
        self.commands_failed.fetch_add(1, Ordering::Relaxed);
    }

    /// Get current snapshot
    pub fn snapshot(&self) -> PoolStatistics {
        PoolStatistics {
            total_created: self.total_created.load(Ordering::Relaxed),
            commands_executed: self.commands_executed.load(Ordering::Relaxed),
            commands_failed: self.commands_failed.load(Ordering::Relaxed),
            ..Default::default()
        }
    }
}

impl Default for StatsCollector {
    fn default() -> Self {
        Self::new()
    }
}

impl Clone for StatsCollector {
    fn clone(&self) -> Self {
        Self {
            total_created: Arc::clone(&self.total_created),
            commands_executed: Arc::clone(&self.commands_executed),
            commands_failed: Arc::clone(&self.commands_failed),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_success_rate() {
        let stats = PoolStatistics {
            total_created: 10,
            commands_executed: 100,
            commands_failed: 10,
            ..Default::default()
        };

        assert_eq!(stats.success_rate(), 90.0);
    }

    #[test]
    fn test_stats_collector() {
        let collector = StatsCollector::new();
        collector.inc_created();
        collector.inc_executed();
        collector.inc_executed();
        collector.inc_failed();

        let snapshot = collector.snapshot();
        assert_eq!(snapshot.total_created, 1);
        assert_eq!(snapshot.commands_executed, 2);
        assert_eq!(snapshot.commands_failed, 1);
    }
}
