use crate::*;

pub struct Allocator {
    channel: kanal::Receiver<Arc<AudioChunk>>,
}

impl Allocator {
    pub fn spawn(buffer_size: usize, pool_size: usize) -> Self {
        let (allocated_buffer_sender, allocated_buffer_receiver) = kanal::bounded(pool_size);

        // Pre-fill the channel with initial buffers
        while let Ok(true) = allocated_buffer_sender.try_send(AudioChunk::allocate(buffer_size)) {}

        let allocator = Allocator {
            channel: allocated_buffer_receiver,
        };

        let allocated_buffer_sender = allocated_buffer_sender.to_async();

        // Spawn the background task that continuously allocates buffers
        tokio::runtime::Handle::current().spawn(async move {
            loop {
                let chunk = AudioChunk::allocate(buffer_size);
                if allocated_buffer_sender.send(chunk).await.is_err() {
                    break;
                }
            }
        });

        allocator
    }
}

impl ChunkFactory for Allocator {
    fn create_chunk(&mut self) -> Result<std::sync::Arc<AudioChunk>> {
        //match self.channel.try_recv_realtime() {
        match self.channel.try_recv() {
            Ok(Some(chunk)) => Ok(chunk),
            _ => Err(LooperError::ChunkAllocation(std::panic::Location::caller())),
        }
    }
}
