//! Closes a subscription
//!
//! The client signals to the relayer to stop listening new events for the given
//! subscription-ID
use std::{collections::VecDeque, ops::Deref};

use crate::{
    common::SerializeDeserialize,
    types::{subscription_id::Error, SubscriptionId},
};
use serde_json::Value;

/// SubscriptionID to stop listening new events to
#[derive(Clone, Debug)]
pub struct Close(pub SubscriptionId);

impl Deref for Close {
    type Target = SubscriptionId;

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

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

    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(Self(subscription_id))
    }
}

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

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

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