//! Common shared types between clients and relayers
pub mod addr;
pub mod content;
pub mod event;
pub mod filter;
pub mod id;
pub mod kind;
pub mod signature;
pub mod subscription_id;
pub mod tag;

pub(crate) mod option_ts_seconds {
    use chrono::{DateTime, LocalResult, TimeZone, Utc};
    use serde::{de, Deserialize, Deserializer, Serializer};

    pub fn serialize<S>(date: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match date {
            Some(date) => super::ts_seconds::serialize(date, serializer),
            None => serializer.serialize_none(),
        }
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<DateTime<Utc>>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let timestamp: Option<i64> = Deserialize::deserialize(deserializer)?;
        let timestamp = if let Some(timestamp) = timestamp {
            timestamp
        } else {
            return Ok(None);
        };

        match Utc.timestamp_opt(timestamp, 0) {
            LocalResult::None => Err(de::Error::custom("Invalid timestamp")),
            LocalResult::Ambiguous(min, max) => Err(de::Error::custom(format!(
                "Timestamp {0} is ambiguous (min={1}, max={2})",
                timestamp, min, max
            ))),
            LocalResult::Single(ts) => Ok(Some(ts)),
        }
    }
}

pub(crate) mod ts_seconds {
    use chrono::{DateTime, LocalResult, TimeZone, Utc};
    use serde::{de, Deserialize, Deserializer, Serializer};

    pub fn serialize<S>(date: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_i64(date.timestamp())
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<Utc>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let timestamp: i64 = Deserialize::deserialize(deserializer)?;

        match Utc.timestamp_opt(timestamp, 0) {
            LocalResult::None => Err(de::Error::custom("Invalid timestamp")),
            LocalResult::Ambiguous(min, max) => Err(de::Error::custom(format!(
                "Timestamp {0} is ambiguous (min={1}, max={2})",
                timestamp, min, max
            ))),
            LocalResult::Single(ts) => Ok(ts),
        }
    }
}

pub use self::{
    addr::Addr,
    content::Content,
    event::{Event, UnsignedEvent},
    filter::Filter,
    id::Id,
    kind::Kind,
    signature::Signature,
    subscription_id::SubscriptionId,
    tag::Tag,
};
