//! Per-graph cumulative metering. Zero overhead when `metrics` feature is absent.
#[cfg(feature = "metrics")]
use std::collections::HashMap;
#[cfg(feature = "metrics")]
use std::sync::atomic::{AtomicU64, Ordering};

pub struct GraphMetrics {
    #[cfg(feature = "metrics")] pub query_total: AtomicU64,
    #[cfg(feature = "metrics")] pub error_total: AtomicU64,
    #[cfg(feature = "metrics")] pub nodes_created: AtomicU64,
    #[cfg(feature = "metrics")] pub edges_created: AtomicU64,
    #[cfg(feature = "metrics")] pub nodes_deleted: AtomicU64,
    #[cfg(feature = "metrics")] pub edges_deleted: AtomicU64,
    #[cfg(feature = "metrics")] pub execute_nanos_total: AtomicU64,
}

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

impl GraphMetrics {
    pub const fn new() -> Self {
        Self {
            #[cfg(feature = "metrics")] query_total: AtomicU64::new(0),
            #[cfg(feature = "metrics")] error_total: AtomicU64::new(0),
            #[cfg(feature = "metrics")] nodes_created: AtomicU64::new(0),
            #[cfg(feature = "metrics")] edges_created: AtomicU64::new(0),
            #[cfg(feature = "metrics")] nodes_deleted: AtomicU64::new(0),
            #[cfg(feature = "metrics")] edges_deleted: AtomicU64::new(0),
            #[cfg(feature = "metrics")] execute_nanos_total: AtomicU64::new(0),
        }
    }

    /// Called after a successful execute() — stats come from QueryStats.
    pub fn record_execute(
        &self,
        elapsed_ns: u64,
        nodes_created: u64,
        edges_created: u64,
        nodes_deleted: u64,
        edges_deleted: u64,
    ) {
        #[cfg(feature = "metrics")]
        {
            self.query_total.fetch_add(1, Ordering::Relaxed);
            self.execute_nanos_total.fetch_add(elapsed_ns, Ordering::Relaxed);
            self.nodes_created.fetch_add(nodes_created, Ordering::Relaxed);
            self.edges_created.fetch_add(edges_created, Ordering::Relaxed);
            self.nodes_deleted.fetch_add(nodes_deleted, Ordering::Relaxed);
            self.edges_deleted.fetch_add(edges_deleted, Ordering::Relaxed);
        }
        // suppress unused variable warnings when feature is disabled
        let _ = (elapsed_ns, nodes_created, edges_created, nodes_deleted, edges_deleted);
    }

    pub fn record_error(&self) {
        #[cfg(feature = "metrics")]
        self.error_total.fetch_add(1, Ordering::Relaxed);
    }

    #[cfg(feature = "metrics")]
    pub fn snapshot(&self) -> HashMap<String, u64> {
        let mut map = HashMap::new();
        map.insert("query_total".to_string(), self.query_total.load(Ordering::Relaxed));
        map.insert("error_total".to_string(), self.error_total.load(Ordering::Relaxed));
        map.insert("nodes_created".to_string(), self.nodes_created.load(Ordering::Relaxed));
        map.insert("edges_created".to_string(), self.edges_created.load(Ordering::Relaxed));
        map.insert("nodes_deleted".to_string(), self.nodes_deleted.load(Ordering::Relaxed));
        map.insert("edges_deleted".to_string(), self.edges_deleted.load(Ordering::Relaxed));
        map.insert("execute_nanos_total".to_string(), self.execute_nanos_total.load(Ordering::Relaxed));
        map
    }
}
