use core::sync::atomic::{AtomicU64, Ordering};

#[derive(Debug, Default, Clone, Copy)]
pub struct PageCacheStatsSnapshot {
    pub file_pages: u64,
    pub file_mapped: u64,
    pub file_dirty: u64,
    pub file_writeback: u64,
    pub shmem_pages: u64,
    pub unevictable: u64,
    pub drop_pagecache: u64,
    pub read_dma_reservations: u64,
    pub invalidation_launder_batches: u64,
    pub invalidation_launder_pages: u64,
}

static FILE_PAGES: AtomicU64 = AtomicU64::new(0);
static FILE_MAPPED: AtomicU64 = AtomicU64::new(0);
static FILE_DIRTY: AtomicU64 = AtomicU64::new(0);
static FILE_WRITEBACK: AtomicU64 = AtomicU64::new(0);
static SHMEM_PAGES: AtomicU64 = AtomicU64::new(0);
static UNEVICTABLE: AtomicU64 = AtomicU64::new(0);
static DROP_PAGECACHE: AtomicU64 = AtomicU64::new(0);
static READ_DMA_RESERVATIONS: AtomicU64 = AtomicU64::new(0);
static INVALIDATION_LAUNDER_BATCHES: AtomicU64 = AtomicU64::new(0);
static INVALIDATION_LAUNDER_PAGES: AtomicU64 = AtomicU64::new(0);

#[inline]
pub fn inc_file_pages() {
    FILE_PAGES.fetch_add(1, Ordering::Relaxed);
}

#[inline]
pub fn dec_file_pages() {
    FILE_PAGES.fetch_sub(1, Ordering::Relaxed);
}

#[inline]
pub fn inc_file_mapped() {
    FILE_MAPPED.fetch_add(1, Ordering::Relaxed);
}

#[inline]
pub fn dec_file_mapped() {
    FILE_MAPPED.fetch_sub(1, Ordering::Relaxed);
}

#[inline]
pub fn inc_file_dirty() {
    FILE_DIRTY.fetch_add(1, Ordering::Relaxed);
}

#[inline]
pub fn dec_file_dirty() {
    FILE_DIRTY.fetch_sub(1, Ordering::Relaxed);
}

#[inline]
pub fn inc_file_writeback() {
    FILE_WRITEBACK.fetch_add(1, Ordering::Relaxed);
}

#[inline]
pub fn dec_file_writeback() {
    FILE_WRITEBACK.fetch_sub(1, Ordering::Relaxed);
}

#[inline]
pub fn inc_shmem_pages() {
    SHMEM_PAGES.fetch_add(1, Ordering::Relaxed);
}

#[inline]
pub fn dec_shmem_pages() {
    SHMEM_PAGES.fetch_sub(1, Ordering::Relaxed);
}

#[inline]
pub fn inc_unevictable() {
    UNEVICTABLE.fetch_add(1, Ordering::Relaxed);
}

#[inline]
pub fn dec_unevictable() {
    UNEVICTABLE.fetch_sub(1, Ordering::Relaxed);
}

#[inline]
pub fn inc_drop_pagecache() {
    DROP_PAGECACHE.fetch_add(1, Ordering::Relaxed);
}

#[inline]
pub fn begin_read_dma_reservation() {
    READ_DMA_RESERVATIONS.fetch_add(1, Ordering::AcqRel);
}

#[inline]
pub fn end_read_dma_reservation() {
    READ_DMA_RESERVATIONS.fetch_sub(1, Ordering::AcqRel);
}

#[inline]
pub fn record_invalidation_launder_batch(pages: usize) {
    INVALIDATION_LAUNDER_BATCHES.fetch_add(1, Ordering::Relaxed);
    INVALIDATION_LAUNDER_PAGES.fetch_add(pages as u64, Ordering::Relaxed);
}

#[inline]
pub fn snapshot() -> PageCacheStatsSnapshot {
    PageCacheStatsSnapshot {
        file_pages: FILE_PAGES.load(Ordering::Relaxed),
        file_mapped: FILE_MAPPED.load(Ordering::Relaxed),
        file_dirty: FILE_DIRTY.load(Ordering::Relaxed),
        file_writeback: FILE_WRITEBACK.load(Ordering::Relaxed),
        shmem_pages: SHMEM_PAGES.load(Ordering::Relaxed),
        unevictable: UNEVICTABLE.load(Ordering::Relaxed),
        drop_pagecache: DROP_PAGECACHE.load(Ordering::Relaxed),
        read_dma_reservations: READ_DMA_RESERVATIONS.load(Ordering::Acquire),
        invalidation_launder_batches: INVALIDATION_LAUNDER_BATCHES.load(Ordering::Relaxed),
        invalidation_launder_pages: INVALIDATION_LAUNDER_PAGES.load(Ordering::Relaxed),
    }
}
