// Staging upload batch — collects writes and flushes to a GPU buffer.

/// Staging upload batch — collects writes and flushes to a GPU buffer.
/// Accumulates byte data on the CPU side, then the caller writes it to
/// a staging buffer in a single `queue.write_buffer()` call.
pub struct UploadBatch {
    data: Vec<u8>,
}

impl UploadBatch {
    pub fn new() -> Self {
        Self { data: Vec::new() }
    }

    /// Append bytes to the batch. Returns the byte offset of the pushed data.
    pub fn push(&mut self, bytes: &[u8]) -> usize {
        let offset = self.data.len();
        self.data.extend_from_slice(bytes);
        offset
    }

    /// Total accumulated bytes.
    pub fn len(&self) -> usize {
        self.data.len()
    }

    /// Whether the batch contains no data.
    pub fn is_empty(&self) -> bool {
        self.data.is_empty()
    }

    /// View the accumulated bytes.
    pub fn as_bytes(&self) -> &[u8] {
        &self.data
    }

    /// Clear all accumulated data for reuse.
    pub fn clear(&mut self) {
        self.data.clear();
    }
}

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

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn new_batch_is_empty() {
        let batch = UploadBatch::new();
        assert!(batch.is_empty());
        assert_eq!(batch.len(), 0);
    }

    #[test]
    fn default_is_empty() {
        let batch = UploadBatch::default();
        assert!(batch.is_empty());
    }

    #[test]
    fn push_returns_offset() {
        let mut batch = UploadBatch::new();
        let off0 = batch.push(&[1, 2, 3, 4]);
        assert_eq!(off0, 0);
        let off1 = batch.push(&[5, 6]);
        assert_eq!(off1, 4);
        assert_eq!(batch.len(), 6);
    }

    #[test]
    fn as_bytes_matches_pushes() {
        let mut batch = UploadBatch::new();
        batch.push(&[0xAA, 0xBB]);
        batch.push(&[0xCC]);
        assert_eq!(batch.as_bytes(), &[0xAA, 0xBB, 0xCC]);
    }

    #[test]
    fn clear_resets() {
        let mut batch = UploadBatch::new();
        batch.push(&[1, 2, 3]);
        batch.clear();
        assert!(batch.is_empty());
        assert_eq!(batch.len(), 0);
    }
}
