use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use time::OffsetDateTime;
use uuid::Uuid;

use super::Identifiable;

pub type MessageID = <Message as Identifiable>::ID;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttributionInfo {
    /// Picture width
    #[serde(rename = "pgensw")]
    pub width: Option<u32>,

    /// Picture height  
    #[serde(rename = "pgensh")]
    pub height: Option<u32>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttachmentMetadata {
    #[serde(rename = "attributionInfo")]
    pub attribution_info: Option<AttributionInfo>,
}

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

    #[serde(rename = "text")]
    pub text: String,

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

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

    /// Array of file transfer GUIDs for attachments
    #[serde(rename = "fileTransferGUIDs", default)]
    pub file_transfer_guids: Vec<String>,

    /// Optional attachment metadata, keyed by attachment GUID
    #[serde(rename = "attachmentMetadata")]
    pub attachment_metadata: Option<HashMap<String, AttachmentMetadata>>,
}

impl Message {
    pub fn builder() -> MessageBuilder {
        MessageBuilder::new()
    }
}

impl Identifiable for Message {
    type ID = String;

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

#[derive(Default)]
pub struct MessageBuilder {
    guid: Option<String>,
    text: Option<String>,
    sender: Option<String>,
    date: Option<OffsetDateTime>,
    file_transfer_guids: Option<Vec<String>>,
    attachment_metadata: Option<HashMap<String, AttachmentMetadata>>,
}

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

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

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

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

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

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

    pub fn attachment_metadata(
        mut self,
        attachment_metadata: HashMap<String, AttachmentMetadata>,
    ) -> Self {
        self.attachment_metadata = Some(attachment_metadata);
        self
    }

    pub fn build(self) -> Message {
        Message {
            guid: self.guid.unwrap_or(Uuid::new_v4().to_string()),
            text: self.text.unwrap_or("".to_string()),
            sender: self.sender,
            date: self.date.unwrap_or(OffsetDateTime::now_utc()),
            file_transfer_guids: self.file_transfer_guids.unwrap_or_default(),
            attachment_metadata: self.attachment_metadata,
        }
    }
}
