use std::{
    mem::take,
    sync::{Arc, Mutex},
};

use crate::Message;

/// Message destination handler
///
/// Normally messages are localized and printed using a
/// [`Writer`](crate::Writer).  This trait allows to implement an
/// alternate behavior (like just saving all raw as done by
/// [`MessageHandler`]).
pub trait MessageHandler<M: Message>
{
    fn write(&self, message: M);
}

/// Raw message buffer
///
/// Instead of localizing and printing messages this buffers raw
/// messages and makes them available with [`get_messages()`](Self::get_messages).
#[derive(Debug, Clone)]
pub struct MessageBuffer<M: Message>
{
    buf: Arc<Mutex<Vec<M>>>,
}

impl<M> MessageHandler<M> for &mut MessageBuffer<M>
where
    M: Message,
{
    fn write(&self, message: M)
    {
        self.buf.lock().unwrap().push(message);
    }
}

impl<M> MessageBuffer<M>
where
    M: Message,
{
    /// Creating a new [`MessageBuffer`]
    ///
    /// This creates a new message buffer.
    #[must_use]
    pub fn new() -> Self
    {
        Self {
            buf: Arc::default(),
        }
    }

    /// Returns the buffered messages
    ///
    /// This function takes and returns the buffered messages.  Taken
    /// messages are removed, so a second call will *not* return the
    /// old messages again, but only the new.
    // This cannot panic.
    #[allow(clippy::missing_panics_doc)]
    #[must_use]
    pub fn get_messages(&self) -> Vec<M>
    {
        take(&mut self.buf.lock().unwrap())
    }
}

impl<M> Default for MessageBuffer<M>
where
    M: Message,
{
    fn default() -> Self
    {
        Self::new()
    }
}
