use crate::models::{message::Message, participant::Participant};
use chrono::{DateTime, NaiveDateTime};
use uuid::Uuid;

#[derive(Clone, Debug)]
pub struct Conversation {
    pub guid: String,
    pub unread_count: u16,
    pub display_name: Option<String>,
    pub last_message_preview: Option<String>,
    pub date: NaiveDateTime,
    pub participants: Vec<Participant>,
}

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

    pub fn into_builder(&self) -> ConversationBuilder {
        ConversationBuilder {
            guid: Some(self.guid.clone()),
            date: self.date,
            participants: None,
            unread_count: Some(self.unread_count),
            last_message_preview: self.last_message_preview.clone(),
            display_name: self.display_name.clone(),
        }
    }

    pub fn merge(&self, other: &Conversation, last_message: Option<&Message>) -> Conversation {
        let mut new_conversation = self.clone();
        new_conversation.unread_count = other.unread_count;
        new_conversation.participants = other.participants.clone();
        new_conversation.display_name = other.display_name.clone();

        if let Some(last_message) = last_message {
            if last_message.date > self.date {
                new_conversation.date = last_message.date;
            }

            if !last_message.text.is_empty() && !last_message.text.trim().is_empty() {
                new_conversation.last_message_preview = Some(last_message.text.clone());
            }
        }

        new_conversation
    }
}

impl PartialEq for Conversation {
    fn eq(&self, other: &Self) -> bool {
        self.guid == other.guid
            && self.unread_count == other.unread_count
            && self.display_name == other.display_name
            && self.last_message_preview == other.last_message_preview
            && self.date == other.date
            && self.participants == other.participants
    }
}

impl From<kordophone::model::Conversation> for Conversation {
    fn from(value: kordophone::model::Conversation) -> Self {
        Self {
            guid: value.guid,
            unread_count: u16::try_from(value.unread_count).unwrap(),
            display_name: value.display_name,
            last_message_preview: value.last_message_preview,
            date: DateTime::from_timestamp(
                value.date.unix_timestamp(),
                value.date.unix_timestamp_nanos().try_into().unwrap_or(0),
            )
            .unwrap()
            .naive_local(),
            participants: value
                .participant_display_names
                .into_iter()
                .map(|p| Participant::Remote {
                    handle: p,
                    contact_id: None,
                }) // todo: this is wrong
                .collect(),
        }
    }
}

#[derive(Default)]
pub struct ConversationBuilder {
    guid: Option<String>,
    date: NaiveDateTime,
    unread_count: Option<u16>,
    last_message_preview: Option<String>,
    participants: Option<Vec<Participant>>,
    display_name: Option<String>,
}

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

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

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

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

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

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

    pub fn display_name(mut self, display_name: &str) -> Self {
        self.display_name = Some(display_name.into());
        self
    }

    pub fn build(&self) -> Conversation {
        Conversation {
            guid: self.guid.clone().unwrap_or(Uuid::new_v4().to_string()),
            unread_count: self.unread_count.unwrap_or(0),
            last_message_preview: self.last_message_preview.clone(),
            display_name: self.display_name.clone(),
            date: self.date,
            participants: self.participants.clone().unwrap_or_default(),
        }
    }
}
