pub mod buffer;
pub mod lease;
pub mod reclaim;
pub mod shared;
pub mod shm;

use std::collections::HashMap;

use core_types::BufferId;

pub use buffer::{Buffer, BufferKind};
pub use lease::{BufferLease, PacketView};
pub use reclaim::{NoopReclaimer, ReclaimPolicy};
pub use shared::SharedBufferDescriptor;
pub use shm::{
    SharedMemoryBufferRef, SharedMemoryReader, SharedMemoryWriter, ShmRateLimitConfig,
    ShmTransportConfig,
};

pub trait BufferLeaseProvider {
    fn allocate(&mut self, data: Vec<u8>) -> BufferLease;
    fn get(&self, id: BufferId) -> Option<BufferLease>;
    fn release(&mut self, id: BufferId);
}

#[derive(Default)]
pub struct SimpleBufferPool {
    next_id: u64,
    buffers: HashMap<BufferId, Buffer>,
    active_leases: usize,
}

impl SimpleBufferPool {
    pub fn new() -> Self {
        Self::default()
    }

    /// Returns the number of buffers currently allocated and not yet released.
    pub fn outstanding_leases(&self) -> usize {
        self.active_leases
    }

    /// Panics (in debug builds and tests) if there are any unreleased buffers.
    /// Use at the end of a test to confirm there are no buffer leaks.
    #[cfg(any(debug_assertions, test))]
    pub fn assert_no_leaks(&self) {
        assert_eq!(
            self.active_leases, 0,
            "buffer leak detected: {} outstanding lease(s)",
            self.active_leases
        );
    }
}

impl BufferLeaseProvider for SimpleBufferPool {
    fn allocate(&mut self, data: Vec<u8>) -> BufferLease {
        self.next_id += 1;
        let buffer = Buffer::from_vec(BufferId::new(self.next_id), data);
        let lease = BufferLease::full(buffer.clone());
        self.buffers.insert(buffer.id, buffer);
        self.active_leases += 1;
        lease
    }

    fn get(&self, id: BufferId) -> Option<BufferLease> {
        self.buffers.get(&id).cloned().map(BufferLease::full)
    }

    fn release(&mut self, id: BufferId) {
        if self.buffers.remove(&id).is_some() {
            self.active_leases = self.active_leases.saturating_sub(1);
        }
    }
}
