use crate::serializers::types::JsonDataUint8Array;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

pub fn serialize<S>(value: &Option<Vec<u8>>, s: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    match value {
        Some(v) => JsonDataUint8Array {
            value: v.to_owned(),
        }
        .serialize(s),
        None => s.serialize_none(),
    }
}

pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
where
    D: Deserializer<'de>,
{
    Option::<JsonDataUint8Array>::deserialize(deserializer).map(|opt| opt.map(|d| d.value))
}

#[cfg(test)]
mod tests {
    use serde::{Deserialize, Serialize};
    use serde_json;

    #[derive(Serialize, Deserialize, PartialEq, Debug)]
    struct TestStruct {
        #[serde(with = "super")]
        value: Option<Vec<u8>>,
    }

    #[test]
    fn serialize_some() {
        let s = TestStruct {
            value: Some(vec![1, 2, 3]),
        };
        let json = serde_json::to_string(&s).expect("serialize");
        assert_eq!(json, r#"{"value":{"__uint8array__":[1,2,3]}}"#);
    }

    #[test]
    fn serialize_none() {
        let s = TestStruct { value: None };
        let json = serde_json::to_string(&s).expect("serialize");
        assert_eq!(json, r#"{"value":null}"#);
    }

    #[test]
    fn deserialize_some() {
        let json = r#"{"value":{"__uint8array__":[1,2,3]}}"#;
        let s: TestStruct = serde_json::from_str(json).expect("deserialize");
        assert_eq!(s.value, Some(vec![1, 2, 3]));
    }

    #[test]
    fn deserialize_none() {
        let json = r#"{"value":null}"#;
        let s: TestStruct = serde_json::from_str(json).expect("deserialize");
        assert_eq!(s.value, None);
    }

    #[test]
    fn round_trip_some() {
        let original = TestStruct {
            value: Some(vec![0, 1, 2, 3, 255]),
        };
        let json = serde_json::to_string(&original).unwrap();
        let decoded: TestStruct = serde_json::from_str(&json).unwrap();
        assert_eq!(decoded.value, original.value);
    }

    #[test]
    fn round_trip_none() {
        let original = TestStruct { value: None };
        let json = serde_json::to_string(&original).unwrap();
        let decoded: TestStruct = serde_json::from_str(&json).unwrap();
        assert_eq!(decoded.value, original.value);
    }
}
