use crate::UID;
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use uuid::Uuid;

pub struct Moo<'cow, T: Clone>(pub Cow<'cow, T>);

pub trait AsMsg: Clone + Serialize {
    fn as_message<'m>(&'m self) -> BaseMessage<'m, Self>
    where
        Moo<'m, Self>: From<&'m Self>,
    {
        BaseMessage::new(self)
    }
}

impl<'cow, M: AsMsg> From<M> for Moo<'cow, M> {
    #[inline]
    fn from(obj: M) -> Moo<'cow, M> {
        Moo(Cow::Owned(obj))
    }
}

impl<'cow, M: AsMsg> From<&'cow M> for Moo<'cow, M> {
    #[inline]
    fn from(obj: &'cow M) -> Moo<'cow, M> {
        Moo(Cow::Borrowed(obj))
    }
}

impl<M: AsMsg> AsMsg for Vec<M> {}

#[derive(Serialize, Deserialize, Debug)]
pub struct BaseMessage<'cow, I: AsMsg> {
    pub id: Uuid,
    inner: Cow<'cow, I>,
}

impl<'cow, I: AsMsg> BaseMessage<'cow, I> {
    pub fn new<C>(inner: C) -> Self
    where
        C: Into<Moo<'cow, I>>,
    {
        let Moo(inner) = inner.into();
        Self {
            id: UID.clone(),
            inner,
        }
    }

    pub fn into_inner(self) -> I {
        self.inner.into_owned()
    }
}