//! Serde Implementations

use crate::{Error, Mic, mic};
#[cfg(feature = "alloc")]
use alloc::{string::String, vec::Vec};
use core::fmt::{Formatter, Result as FmtResult};
use serde::{
    Deserialize, Deserializer, Serialize, Serializer,
    de::{Error as DeError, Unexpected, Visitor},
};

impl Serialize for mic {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_str(self.as_str())
    }
}

impl Serialize for Mic {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        serializer.serialize_str(self.as_str())
    }
}

struct MicVisitor;

impl<'v> Visitor<'v> for MicVisitor {
    type Value = &'v mic;

    fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
        formatter.write_str("a 4-character string or byte-string value")
    }

    fn visit_borrowed_bytes<E: DeError>(self, v: &'v [u8]) -> Result<Self::Value, E> {
        mic::from_bytes(v).map_err(|err| match err {
            Error::InvalidCharacter(pos) => {
                DeError::invalid_value(Unexpected::Bytes(&[v[pos]]), &"A-Z, 0-9")
            }
            Error::InvalidLength(actual, _expected) => {
                DeError::invalid_length(actual, &"4 ascii digits or upper-case characters")
            }
        })
    }

    fn visit_borrowed_str<E: DeError>(self, v: &'v str) -> Result<Self::Value, E> {
        self.visit_borrowed_bytes(v.as_bytes())
    }
}

impl<'de> Deserialize<'de> for &'de mic {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_string(MicVisitor)
    }
}

struct OwnedMicVisitor;

impl<'v> Visitor<'v> for OwnedMicVisitor {
    type Value = Mic;

    fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
        formatter.write_str("a 4-character string or byte-string value")
    }

    fn visit_borrowed_bytes<E: DeError>(self, v: &'v [u8]) -> Result<Self::Value, E> {
        Mic::from_bytes(v).map_err(|err| match err {
            Error::InvalidCharacter(pos) => {
                DeError::invalid_value(Unexpected::Bytes(&[v[pos]]), &"A-Z, 0-9")
            }
            Error::InvalidLength(actual, _expected) => {
                DeError::invalid_length(actual, &"4 ascii digits or upper-case characters")
            }
        })
    }

    fn visit_borrowed_str<E: DeError>(self, v: &'v str) -> Result<Self::Value, E> {
        self.visit_borrowed_bytes(v.as_bytes())
    }

    fn visit_bytes<E: DeError>(self, v: &[u8]) -> Result<Self::Value, E> {
        self.visit_borrowed_bytes(v)
    }

    fn visit_str<E: DeError>(self, v: &str) -> Result<Self::Value, E> {
        self.visit_borrowed_str(v)
    }

    #[cfg(feature = "alloc")]
    fn visit_string<E: DeError>(self, v: String) -> Result<Self::Value, E> {
        self.visit_borrowed_str(&v)
    }

    #[cfg(feature = "alloc")]
    fn visit_byte_buf<E: DeError>(self, v: Vec<u8>) -> Result<Self::Value, E> {
        self.visit_borrowed_bytes(&v)
    }
}

impl<'de> Deserialize<'de> for Mic {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        deserializer.deserialize_str(OwnedMicVisitor)
    }
}

#[cfg(test)]
mod test {
    use crate::Mic;
    use core::str::FromStr;

    #[test]
    fn serde_roundtrip() {
        let start = Mic::from_str("IEXG").expect("ctor");
        let serde = serde_json::to_string(&start).expect("ser");
        assert_eq!("\"IEXG\"", serde);

        let end = serde_json::from_str::<Mic>(&serde).expect("end");
        assert_eq!(start, end);
    }
}
