use crate::{Prefix, Puuid};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::str::FromStr;

impl<T: Prefix> Serialize for Puuid<T> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str(&self.to_string())
    }
}

impl<'de, T: Prefix> Deserialize<'de> for Puuid<T> {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        Self::from_str(&s).map_err(de::Error::custom)
    }
}

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

    prefix!(Api, "api");
    type ApiId = Puuid<Api>;

    #[test]
    fn test_serde_json() {
        let id = ApiId::new_v7();
        let json = serde_json::to_string(&id).unwrap();

        // Ensure it looks like a string in JSON
        assert!(json.starts_with("\"api_"));

        let parsed: ApiId = serde_json::from_str(&json).unwrap();
        assert_eq!(id, parsed);
    }

    #[test]
    fn test_serde_deserialize_fail() {
        // A JSON string with the wrong prefix
        let bad_json = "\"wrong_00000000-0000-0000-0000-000000000000\"";

        let result: Result<ApiId, _> = serde_json::from_str(bad_json);

        assert!(result.is_err());
        let err_msg = result.unwrap_err().to_string();
        assert!(err_msg.contains("Wrong prefix"));
    }
}
