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

pub trait ToMsg: Clone { //+ Serialize + DeserializeOwned {
    fn as_message<'m>(&'m self) -> Message<'m, Self>
    where Cow<'m, Self>: From<&'m Self> {
        Message::new(self)
    }
}

// 1. Cow<'_, ItemWrap<I>> - failed, Message::new needs val or ref
// 2. ItemWrap<Cow<'_, I>> - can't impl From<Vec<...>> for Cow

#[derive(Serialize, Deserialize, Debug)]
pub struct Message<'cow, I>
where I: ToMsg {
    pub id: Uuid,
    pub item: Cow<'cow, I>
}

impl<'cow, I> Message<'cow, I>
    where I: ToMsg
{
    pub fn new<C>(item: C) -> Self
    where C: Into<Cow<'cow, I>> {
        Self {
            id: UID.clone(),
            item: item.into()
        }
    }

    pub fn into_item(self) -> I {
        self.item.into_owned()
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RawMsg(pub String);

impl<T: ToMsg> ToMsg for Vec<T> {} //TODO: impl this for all collections


#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ItemWrap<T: ToMsg>(pub T);

impl<T: ToMsg> ToMsg for ItemWrap<T> {}

impl<'cow, T: ToMsg> From<ItemWrap<T>> for Cow<'cow, ItemWrap<T>> {
    fn from(obj: ItemWrap<T>) -> Cow<'cow, ItemWrap<T>> {
        Cow::Owned(obj)
    }
}

impl<'cow, T: ToMsg> From<&'cow ItemWrap<T>> for Cow<'cow, ItemWrap<T>> {
    fn from(obj: &'cow ItemWrap<T>) -> Cow<'cow, ItemWrap<T>> {
        Cow::Borrowed(obj)
    }
}

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

    #[test]
    fn test_create_message_owned() {
        let item = String::from("QWEDSA");
        let msg_raw = Message {
            id: *UID,
            item: Cow::Owned(item.clone())
        };
        let msg = Message::new(item);
        assert_eq!(msg_raw.item, msg.item);
    }
}*/