use std::ops::Range;

use core_types::BufferId;

use crate::buffer::Buffer;

#[derive(Clone, Debug)]
pub struct BufferLease {
    buffer: Buffer,
    range: Range<usize>,
}

impl BufferLease {
    pub fn full(buffer: Buffer) -> Self {
        let len = buffer.len();
        Self {
            buffer,
            range: 0..len,
        }
    }

    pub fn buffer_id(&self) -> BufferId {
        self.buffer.id
    }

    pub fn len(&self) -> usize {
        self.range.end.saturating_sub(self.range.start)
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn as_slice(&self) -> &[u8] {
        &self.buffer.as_slice()[self.range.clone()]
    }

    pub fn slice(&self, start: usize, end: usize) -> Option<Self> {
        if start > end || self.range.start + end > self.range.end {
            return None;
        }
        Some(Self {
            buffer: self.buffer.clone(),
            range: (self.range.start + start)..(self.range.start + end),
        })
    }

    pub fn view(&self) -> PacketView<'_> {
        PacketView {
            buffer_id: self.buffer.id,
            bytes: self.as_slice(),
        }
    }
}

#[derive(Clone, Copy, Debug)]
pub struct PacketView<'a> {
    pub buffer_id: BufferId,
    pub bytes: &'a [u8],
}
