//! End of Storage Events
//!
//! This is how to the relayer signals the client they gave all the stored
//! messages with the requested filter. Future events will be sent, as they
//! appear to this relayer
use crate::{
    common::SerializeDeserialize,
    types::{subscription_id::Error, SubscriptionId},
};
use serde_json::Value;
use std::{collections::VecDeque, ops::Deref};

/// This is how to the relayer signals the client they gave all the stored
/// messages with the requested filter. Future events will be sent, as they
/// appear to this relayer
#[derive(Clone, Debug)]
pub struct EndOfStoredEvents(pub SubscriptionId);

impl Deref for EndOfStoredEvents {
    type Target = SubscriptionId;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl SerializeDeserialize for EndOfStoredEvents {
    fn get_tag() -> &'static str {
        "EOSE"
    }

    fn serialize(&self) -> Result<Vec<Value>, String> {
        Ok(vec![
            Value::String(Self::get_tag().to_owned()),
            Value::String((*self.0).to_owned()),
        ])
    }

    fn deserialize(args: VecDeque<Value>) -> Result<Self, String> {
        if args.is_empty() {
            return Err("Invalid length".to_owned());
        }
        let subscription_id: SubscriptionId = args[0]
            .as_str()
            .ok_or_else(|| "Invalid message, expected string".to_owned())?
            .try_into()
            .map_err(|e: Error| e.to_string())?;
        Ok(EndOfStoredEvents(subscription_id))
    }
}

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

    #[test]
    fn parse() {
        let json = r#"["EOSE", "test"]"#;
        let message: Response = serde_json::from_str(json).expect("message");
        assert!(message.as_end_of_stored_events().is_some());
    }

    #[test]
    fn serialize() {
        let notice = EndOfStoredEvents("test".try_into().expect("v"));
        let m: Response = notice.into();
        assert_eq!(
            r#"["EOSE","test"]"#,
            serde_json::to_string(&m).expect("valid json")
        );
    }
}
