//! Serde serialization and deserialization for `DataValue`.
//!
//! This module implements the `Serialize` and `Deserialize` traits for `DataValue`,
//! enabling seamless conversion to and from various serialization formats supported
//! by serde (JSON, YAML, TOML, etc.).
//!
//! # Examples
//!
//! ```rust
//! use trs_data_value::DataValue;
//! use serde_json;
//!
//! let value = DataValue::U32(42);
//! let json = serde_json::to_string(&value).unwrap();
//! assert_eq!(json, "42");
//!
//! let deserialized: DataValue = serde_json::from_str("42").unwrap();
//! assert_eq!(deserialized, DataValue::U64(42)); // JSON numbers deserialize as U64
//! ```

use std::{collections::HashMap, fmt};

use serde::{
    de::{Deserialize, Deserializer, MapAccess, Visitor},
    ser::{Serialize, SerializeMap},
};

use super::DataValue;

/// A Visitor is a type that holds methods that a Deserializer can drive
/// depending on what is contained in the input data.
struct DataValueVisitor;

// This is the trait that Deserializers are going to be driving. There
// is one method for each type of data that our type knows how to
// deserialize from.
impl<'de> Visitor<'de> for DataValueVisitor {
    // The type that our Visitor is going to produce.
    type Value = DataValue;

    // Format a message stating what data this Visitor expects to receive.
    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("a very special map")
    }

    fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(DataValue::Bool(v))
    }

    fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(DataValue::I64(v))
    }

    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(DataValue::U64(v))
    }

    fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(DataValue::F64(v))
    }

    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(DataValue::String(v.into()))
    }

    fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(DataValue::String(v.into()))
    }

    #[inline]
    fn visit_unit<E>(self) -> Result<Self::Value, E> {
        Ok(DataValue::Null)
    }

    fn visit_f32<E>(self, v: f32) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(DataValue::F32(v))
    }

    fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(DataValue::U8(v))
    }

    fn visit_i128<E>(self, v: i128) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(DataValue::I128(v))
    }

    fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(DataValue::U128(v))
    }

    fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(DataValue::Bytes(v.into()))
    }

    fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(DataValue::Bytes(v))
    }

    fn visit_none<E>(self) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        Ok(DataValue::Null)
    }

    fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        Deserialize::deserialize(deserializer)
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
    where
        A: serde::de::SeqAccess<'de>,
    {
        let mut vec = Vec::new();
        while let Ok(Some(value)) = seq.next_element() {
            vec.push(value);
        }
        Ok(DataValue::Vec(vec))
    }

    // Deserialize MyMap from an abstract "map" provided by the
    // Deserializer. The MapAccess input is a callback provided by
    // the Deserializer to let us see each entry in the map.
    fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
    where
        M: MapAccess<'de>,
    {
        let mut map = HashMap::with_capacity(access.size_hint().unwrap_or(0));

        // While there are entries remaining in the input, add them
        // into our map.
        while let Some((key, value)) = access.next_entry()? {
            map.insert(key, value);
        }

        Ok(DataValue::Map(map))
    }
}

// This is the trait that informs Serde how to deserialize MyMap.
impl<'de> Deserialize<'de> for DataValue {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_any(DataValueVisitor)
    }
}

impl Serialize for DataValue {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        match self {
            DataValue::Bool(v) => serializer.serialize_bool(*v),
            DataValue::I64(v) => serializer.serialize_i64(*v),
            DataValue::U64(v) => serializer.serialize_u64(*v),
            DataValue::F64(v) => serializer.serialize_f64(*v),
            DataValue::String(v) => serializer.serialize_str(v),
            DataValue::F32(v) => serializer.serialize_f32(*v),
            DataValue::U8(v) => serializer.serialize_u8(*v),
            DataValue::I128(v) => serializer.serialize_i128(*v),
            DataValue::U128(v) => serializer.serialize_u128(*v),
            DataValue::Bytes(v) => serializer.serialize_bytes(v),
            DataValue::Vec(v) => v.serialize(serializer),
            DataValue::Map(v) => {
                // v.serialize(serializer)
                let mut map = serializer.serialize_map(Some(v.len()))?;
                for (k, v) in v {
                    map.serialize_entry(k, v)?;
                }
                map.end()
            }
            DataValue::Null => serializer.serialize_unit(),
            DataValue::I32(v) => serializer.serialize_i32(*v),
            DataValue::U32(v) => serializer.serialize_u32(*v),
            DataValue::EnumNumber(v) => serializer.serialize_i32(*v),
        }
    }
}

#[cfg(test)]
mod test {

    use super::*;
    use rstest::*;

    #[rstest]
    #[case::bool(true, DataValue::Bool(true))]
    #[case::i64(-42i64, DataValue::I64(-42))]
    #[case::f64(42.0f64, DataValue::F64(42.0))]
    #[case::str("test", DataValue::String("test".into()))]
    #[case::string("test".to_string(), DataValue::String("test".into()))]
    #[case::seq(vec![DataValue::I64(-1), DataValue::I64(-2)], DataValue::Vec(vec![DataValue::I64(-1), DataValue::I64(-2)]))]
    #[case::map({
        let mut map = HashMap::new();
        map.insert("key".to_string(), DataValue::U64(42));
        map
    }, DataValue::Map(crate::stdhashmap!("key" => DataValue::U64(42))))]
    fn test_deserialize(#[case] input: impl Into<DataValue>, #[case] expected: DataValue) {
        let input = input.into();
        let serialized = serde_json::to_value(&input);
        assert!(serialized.is_ok(), "{:?}", serialized);
        println!("{:?}", serialized);
        let deserialized: Result<DataValue, _> = serde_json::from_value(serialized.unwrap());
        assert!(deserialized.is_ok(), "{:?}", deserialized);
        assert_eq!(deserialized.unwrap(), expected);
    }

    #[derive(Debug, thiserror::Error)]
    enum DummyError {
        #[error("Custom error: {0}")]
        Custom(String),
    }
    impl serde::de::Error for DummyError {
        #[cold]
        fn custom<T: fmt::Display>(msg: T) -> Self {
            Self::Custom(msg.to_string())
        }
    }

    #[rstest]
    fn test_visitor() {
        let v = DataValueVisitor.visit_bool::<DummyError>(true);
        assert!(v.is_ok());
        assert_eq!(v.unwrap(), DataValue::Bool(true));
        let v = DataValueVisitor.visit_i64::<DummyError>(-42);
        assert!(v.is_ok());
        assert_eq!(v.unwrap(), DataValue::I64(-42));
        let v = DataValueVisitor.visit_u64::<DummyError>(42);
        assert!(v.is_ok());
        assert_eq!(v.unwrap(), DataValue::U64(42));
        let v = DataValueVisitor.visit_f64::<DummyError>(42.0);
        assert!(v.is_ok());
        assert_eq!(v.unwrap(), DataValue::F64(42.0));
        let v = DataValueVisitor.visit_str::<DummyError>("test");
        assert!(v.is_ok());
        assert_eq!(v.unwrap(), DataValue::String("test".into()));
        let v = DataValueVisitor.visit_string::<DummyError>("test".to_string());
        assert!(v.is_ok());
        assert_eq!(v.unwrap(), DataValue::String("test".into()));
        let v = DataValueVisitor.visit_f32::<DummyError>(42.0);
        assert!(v.is_ok());
        assert_eq!(v.unwrap(), DataValue::F32(42.0));
        let v = DataValueVisitor.visit_u8::<DummyError>(42);
        assert!(v.is_ok());
        assert_eq!(v.unwrap(), DataValue::U8(42));
        let v = DataValueVisitor.visit_i128::<DummyError>(i128::MAX);
        assert!(v.is_ok());
        assert_eq!(v.unwrap(), DataValue::I128(i128::MAX));
        let v = DataValueVisitor.visit_u128::<DummyError>(u128::MAX);
        assert!(v.is_ok());
        assert_eq!(v.unwrap(), DataValue::U128(u128::MAX));
        let v = DataValueVisitor.visit_bytes::<DummyError>(b"test");
        assert!(v.is_ok());
        assert_eq!(v.unwrap(), DataValue::Bytes(b"test".to_vec()));
        let v = DataValueVisitor.visit_byte_buf::<DummyError>(b"test".to_vec());
        assert!(v.is_ok());
        assert_eq!(v.unwrap(), DataValue::Bytes(b"test".to_vec()));
        let v = DataValueVisitor.visit_none::<DummyError>();
        assert!(v.is_ok());
        assert_eq!(v.unwrap(), DataValue::Null);
    }

    #[rstest]
    fn serde_simple() {
        let v: Result<Vec<DataValue>, _> = serde_json::from_str(
            r#"[
            253780,
            0.009369421750307085,
            1633222860381359,
            8,
            5,
            true,
            0.16074353018902807,
            0.4461714007722576,
            null,
            0.3,
            0.3,
            0.3,
            -4.660890306625259,
            null,
            0
        ]"#,
        );
        assert!(v.is_ok(), "{v:?}");
    }

    #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
    struct S {
        v: Option<DataValue>,
    }

    #[rstest]
    #[case(S {v: None})]
    // #[case(S {v: Some(DataValue::Null)})]
    fn serde_struct(#[case] e: S) {
        let serialized = serde_json::to_string(&e).expect("should be ok");
        let deserialize: S = serde_json::from_str(&serialized).expect("should be ok deserialize");

        assert_eq!(e, deserialize);
    }
}
