use serde::Deserialize;
use time::OffsetDateTime;
use uuid::Uuid;

use super::Identifiable;
use crate::model::message::Message;

pub type ConversationID = <Conversation as Identifiable>::ID;

#[derive(Debug, Clone, Deserialize)]
pub struct Conversation {
    pub guid: String,

    #[serde(with = "time::serde::iso8601")]
    pub date: OffsetDateTime,

    #[serde(rename = "unreadCount")]
    pub unread_count: i32,

    #[serde(rename = "lastMessagePreview")]
    pub last_message_preview: Option<String>,

    #[serde(rename = "participantDisplayNames")]
    pub participant_display_names: Vec<String>,

    #[serde(rename = "displayName")]
    pub display_name: Option<String>,

    #[serde(rename = "lastMessage")]
    pub last_message: Option<Message>,
}

impl Conversation {
    pub fn builder() -> ConversationBuilder {
        ConversationBuilder::new()
    }
}

impl Identifiable for Conversation {
    type ID = String;

    fn id(&self) -> &Self::ID {
        &self.guid
    }
}

#[derive(Default)]
pub struct ConversationBuilder {
    guid: Option<String>,
    date: Option<OffsetDateTime>,
    unread_count: Option<i32>,
    last_message_preview: Option<String>,
    participant_display_names: Option<Vec<String>>,
    display_name: Option<String>,
    last_message: Option<Message>,
}

impl ConversationBuilder {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn guid(mut self, guid: String) -> Self {
        self.guid = Some(guid);
        self
    }

    pub fn date(mut self, date: OffsetDateTime) -> Self {
        self.date = Some(date);
        self
    }

    pub fn unread_count(mut self, unread_count: i32) -> Self {
        self.unread_count = Some(unread_count);
        self
    }

    pub fn last_message_preview(mut self, last_message_preview: String) -> Self {
        self.last_message_preview = Some(last_message_preview);
        self
    }

    pub fn participant_display_names(mut self, participant_display_names: Vec<String>) -> Self {
        self.participant_display_names = Some(participant_display_names);
        self
    }

    pub fn display_name<T>(mut self, display_name: T) -> Self
    where
        T: Into<String>,
    {
        self.display_name = Some(display_name.into());
        self
    }

    pub fn last_message(mut self, last_message: Message) -> Self {
        self.last_message = Some(last_message);
        self
    }

    pub fn build(self) -> Conversation {
        Conversation {
            guid: self.guid.unwrap_or(Uuid::new_v4().to_string()),
            date: self.date.unwrap_or(OffsetDateTime::now_utc()),
            unread_count: self.unread_count.unwrap_or(0),
            last_message_preview: self.last_message_preview,
            participant_display_names: self.participant_display_names.unwrap_or_default(),
            display_name: self.display_name,
            last_message: self.last_message,
        }
    }
}
