//! Filters
//!
//! This is used for clients to requests for events and subscribe to new events.
//!
//! Each property is treated as an AND, but a vector of filters can be provided,
//! and they will be treated as OR.
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

use super::Kind;

/// Filter
#[derive(Serialize, Deserialize, Default, Debug, Clone)]
pub struct Filter {
    /// Fetch events by their Id, or subscribe
    ///
    /// A full Id can be provided, or a prefix.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub ids: Vec<super::Addr>,
    /// Fetch events by a public key, or a prefix
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub authors: Vec<super::Addr>,
    /// Fetch events by their kinds
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub kinds: Vec<Kind>,
    /// Fetch events that has tag references to a given event id
    #[serde(default, skip_serializing_if = "Vec::is_empty", rename = "#e")]
    pub references_to_event: Vec<super::Addr>,
    /// Fetches events that has a tag to a public key
    #[serde(default, skip_serializing_if = "Vec::is_empty", rename = "#p")]
    pub references_to_public_key: Vec<super::Addr>,
    /// Fetch events newer to this given timestamp
    #[serde(
        default,
        with = "super::option_ts_seconds",
        skip_serializing_if = "Option::is_none"
    )]
    pub since: Option<DateTime<Utc>>,
    /// Fetch events older to this timestamp
    #[serde(
        default,
        with = "super::option_ts_seconds",
        skip_serializing_if = "Option::is_none"
    )]
    pub until: Option<DateTime<Utc>>,
    /// Has a limit to fetch stored events
    #[serde(default, skip_serializing_if = "is_zero")]
    pub limit: u64,
}

#[inline]
fn is_zero(number: &u64) -> bool {
    *number == 0
}

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

    #[test]
    fn deserialize() {
        let json = "{\"authors\":[\"c0f0f1\", \"1234567901\"]}";
        let obj: Result<Filter, _> = serde_json::from_str(&json);
        assert!(obj.is_ok());
    }

    #[test]
    fn serialize() {
        let now = Utc::now();
        let x = Filter {
            since: Some(now),
            ..Default::default()
        };

        assert_eq!(
            format!("{}\"since\":{:?}{}", "{", now.timestamp(), "}"),
            serde_json::to_string(&x).expect("valid json")
        );
    }
}
