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

/// Snapshot of cache operations recorded by [`CacheStats`].
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct CacheStatsSnapshot {
    /// Successful cache reads.
    pub hits: u64,
    /// Cache misses that required a loader call.
    pub misses: u64,
    /// Negative cache hits for known not-found values.
    pub negative_hits: u64,
    /// Loader failures.
    pub loader_errors: u64,
    /// Cache write failures.
    pub set_errors: u64,
    /// Cache delete failures.
    pub delete_errors: u64,
}

#[derive(Debug, Default)]
struct CacheStatsInner {
    hits: AtomicU64,
    misses: AtomicU64,
    negative_hits: AtomicU64,
    loader_errors: AtomicU64,
    set_errors: AtomicU64,
    delete_errors: AtomicU64,
}

/// Shared cache statistics collector.
#[derive(Debug, Clone, Default)]
pub struct CacheStats {
    inner: Arc<CacheStatsInner>,
}

impl CacheStats {
    /// Records a cache hit.
    pub fn record_hit(&self) {
        self.inner.hits.fetch_add(1, Ordering::Relaxed);
    }

    /// Records a cache miss.
    pub fn record_miss(&self) {
        self.inner.misses.fetch_add(1, Ordering::Relaxed);
    }

    /// Records a negative cache hit.
    pub fn record_negative_hit(&self) {
        self.inner.negative_hits.fetch_add(1, Ordering::Relaxed);
    }

    /// Records a loader error.
    pub fn record_loader_error(&self) {
        self.inner.loader_errors.fetch_add(1, Ordering::Relaxed);
    }

    /// Records a cache write error.
    pub fn record_set_error(&self) {
        self.inner.set_errors.fetch_add(1, Ordering::Relaxed);
    }

    /// Records a cache delete error.
    pub fn record_delete_error(&self) {
        self.inner.delete_errors.fetch_add(1, Ordering::Relaxed);
    }

    /// Returns the current counters.
    pub fn snapshot(&self) -> CacheStatsSnapshot {
        CacheStatsSnapshot {
            hits: self.inner.hits.load(Ordering::Relaxed),
            misses: self.inner.misses.load(Ordering::Relaxed),
            negative_hits: self.inner.negative_hits.load(Ordering::Relaxed),
            loader_errors: self.inner.loader_errors.load(Ordering::Relaxed),
            set_errors: self.inner.set_errors.load(Ordering::Relaxed),
            delete_errors: self.inner.delete_errors.load(Ordering::Relaxed),
        }
    }
}
