#![allow(dead_code)]
// (C) Copyright 2022 Automated Design Corp. All Rights Reserved.
// File Created: Sunday, 3rd April 2022 9:03:04 pm
//

//! Variant type used for communications and other purposes.
//! A good example of a Variant type used in a similar application
//! is in the locka99/opcua implementation found here:
//! https://github.com/locka99/opcua/blob/master/lib/src/types/variant.rs
//!
//!
//! Notes:
//! - Objects are stored in IndexMap, not HashMap, to maintain order for serialization to bytes.
//!
//!
//! Examples:
//!
//! Array
//! ```
//! use mechutil::variant::VariantValue;
//! // Initialize an empty Vec<VariantValue> for the array elements.
//! let mut array_elements: Vec<VariantValue> = Vec::new();
//!
//! // Add some data to the array.
//! // For example, let's add a mix of integers and strings.
//! array_elements.push(VariantValue::Int32(10));
//! array_elements.push(VariantValue::String("Hello".to_string()));
//! array_elements.push(VariantValue::Real64(3.14));
//!
//! // Now, create a VariantValue::Array with this vector.
//! let mut array = VariantValue::Array(array_elements);
//!
//! // To demonstrate accessing and modifying the array,
//! // let's add another element to the VariantValue::Array.
//!
//! // Direct manipulation like this requires knowing the exact type,
//! // so in real-world scenarios, pattern matching or direct access with caution is advisable.
//! if let VariantValue::Array(ref mut vec) = array {
//!     // Add a new element to the array.
//!     vec.push(VariantValue::Bit(true));
//! }
//!
//! println!("{:?}", array);
//! ```
//!
//!
//!
//! Object
//! ```
//! use indexmap::IndexMap;
//! use mechutil::variant::VariantValue;
//!
//! // Initialize an empty IndexMap.
//! let mut map: IndexMap<String, VariantValue> = IndexMap::new();
//!
//! // Add some data to the map.
//! // For example, let's add a string and an integer.
//! map.insert("key1".to_string(), VariantValue::String("value1".to_string()));
//! map.insert("key2".to_string(), VariantValue::Int32(42));
//!
//! // Now, create a VariantValue::Object with this map.
//! let mut ret = VariantValue::Object(Box::new(map));
//!
//! // To demonstrate accessing and modifying the object,
//! // let's add another value to the object.
//!
//! // Access the IndexMap directly from the VariantValue::Object variant.
//! // Note: You need to do pattern matching or use if let / match statements
//! // for safer access in real-world scenarios. This example assumes the direct access for simplicity.
//! if let VariantValue::Object(ref mut boxed_map) = ret {
//!     // Insert a new key-value pair.
//!     boxed_map.insert("key3".to_string(), VariantValue::Real64(3.14));
//! }
//!
//! println!("{:?}", ret);
//! ```

use anyhow::anyhow;
use indexmap::IndexMap;
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use serde::Deserialize;
use serde::Serialize;
use std::fmt;

#[cfg(test)]
use log::{trace, warn};

/// The variant type id is the type of the variant but without its payload.
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, FromPrimitive)]
#[repr(i16)]
#[serde(into = "i16", from = "i16")] // Directly convert to and from i16
pub enum VariantTypeId {
    Null = 0,
    Bit = 1,
    Byte = 2,
    SByte = 3,
    Int16 = 4,
    UInt16 = 5,
    Int32 = 6,
    UInt32 = 7,
    Int64 = 8,
    UInt64 = 9,
    Real32 = 10,
    Real64 = 11,
    String = 12,
    Array = 13,
    Object = 14,
    // DateTime,
    // Guid,
    // StatusCode,
    // ByteString,
    // XmlElement,
    // QualifiedName,
    // LocalizedText,
    // NodeId,
    // ExpandedNodeId,
    // ExtensionObject,
    // Variant,
    // DataValue,
    // Diagnostic,
    // Array,
}

impl From<VariantTypeId> for i16 {
    fn from(variant: VariantTypeId) -> Self {
        variant as i16
    }
}

impl From<i16> for VariantTypeId {
    fn from(value: i16) -> Self {
        VariantTypeId::from_i16(value).unwrap()
    }
}

impl fmt::Display for VariantTypeId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let type_str = match self {
            VariantTypeId::Null => "Null",
            VariantTypeId::Bit => "Bit",
            VariantTypeId::Byte => "Byte",
            VariantTypeId::SByte => "SByte",
            VariantTypeId::Int16 => "Int16",
            VariantTypeId::UInt16 => "UInt16",
            VariantTypeId::Int32 => "Int32",
            VariantTypeId::UInt32 => "UInt32",
            VariantTypeId::Int64 => "Int64",
            VariantTypeId::UInt64 => "UInt64",
            VariantTypeId::Real32 => "Real32",
            VariantTypeId::Real64 => "Real64",
            VariantTypeId::String => "String",
            VariantTypeId::Array => "Array",
            VariantTypeId::Object => "Object",
            // Future types can be added here
        };
        write!(f, "{}", type_str)
    }
}

/// Stores a variant value as found in a remote industrial controller.
///
///
/// If you just want to check if enum is currently holding specific variant,
/// you can assert and matches:
/// ```
/// use mechutil::variant::VariantValue;
/// let tst = VariantValue::Byte(243);
/// assert!(matches!(tst, VariantValue::Byte(_))); // Just checking variant of byte type
/// assert!(matches!(tst, VariantValue::Byte(243))); // Checking variant and data
/// assert!(!matches!(tst, VariantValue::Int32(_))); // Is the underlying value an Int32?
/// ```
#[derive(Clone, Debug, Default, Serialize, PartialEq, Deserialize)]
pub enum VariantValue {
    #[default]
    Null,
    Bit(bool),
    Byte(u8),
    SByte(i8),
    Int16(i16),
    UInt16(u16),
    Int32(i32),
    UInt32(u32),
    Int64(i64),
    UInt64(u64),
    Real32(f32),
    Real64(f64),
    String(String),
    Array(Vec<VariantValue>),
    Object(Box<IndexMap<String, VariantValue>>),
}

impl VariantValue {
    /// Convert a serde_json::Value to a VariantValue
    pub fn from_json(value: &serde_json::Value) -> Result<Self, anyhow::Error> {
        match value {
            serde_json::Value::Null => Ok(VariantValue::Null),
            serde_json::Value::Bool(b) => Ok(VariantValue::Bit(*b)),
            serde_json::Value::Number(num) => {
                if let Some(int) = num.as_i64() {
                    // Decide based on the size of the integer which variant to use
                    match int {
                        i if i >= i8::MIN as i64 && i <= i8::MAX as i64 => {
                            Ok(VariantValue::SByte(int as i8))
                        }
                        i if i >= i16::MIN as i64 && i <= i16::MAX as i64 => {
                            Ok(VariantValue::Int16(int as i16))
                        }
                        i if i >= i32::MIN as i64 && i <= i32::MAX as i64 => {
                            Ok(VariantValue::Int32(int as i32))
                        }
                        _i => Ok(VariantValue::Int64(int)),
                    }
                } else if let Some(uint) = num.as_u64() {
                    match uint {
                        u if u <= u8::MAX as u64 => Ok(VariantValue::Byte(uint as u8)),
                        u if u <= u16::MAX as u64 => Ok(VariantValue::UInt16(uint as u16)),
                        u if u <= u32::MAX as u64 => Ok(VariantValue::UInt32(uint as u32)),
                        _u => Ok(VariantValue::UInt64(uint)),
                    }
                } else if let Some(float) = num.as_f64() {
                    // You might want to adjust precision handling here
                    Ok(VariantValue::Real64(float))
                } else {
                    Err(anyhow!("Unsupported number type"))
                }
            }
            serde_json::Value::String(s) => Ok(VariantValue::String(s.clone())),
            serde_json::Value::Array(arr) => {
                let mut elements = vec![];
                for item in arr {
                    elements.push(VariantValue::from_json(item)?);
                }
                Ok(VariantValue::Array(elements))
            }
            serde_json::Value::Object(obj) => {
                let mut map = IndexMap::new();
                for (key, value) in obj {
                    map.insert(key.clone(), VariantValue::from_json(value)?);
                }
                Ok(VariantValue::Object(Box::new(map)))
            }
        }
    }

    /// Returns TRUE if the underlying value is Null.
    pub fn is_null(&self) -> bool {
        match *self {
            VariantValue::Null => {
                return true;
            }
            _ => {
                return false;
            }
        }
    }

    /// Returns the VariantTypeId based upon the underlying type of the VariantValue.
    pub fn get_type_id(&self) -> VariantTypeId {
        match self {
            VariantValue::Null => VariantTypeId::Null,
            VariantValue::Bit(_) => VariantTypeId::Bit,
            VariantValue::Byte(_) => VariantTypeId::Byte,
            VariantValue::SByte(_) => VariantTypeId::SByte,
            VariantValue::Int16(_) => VariantTypeId::Int16,
            VariantValue::UInt16(_) => VariantTypeId::UInt16,
            VariantValue::Int32(_) => VariantTypeId::Int32,
            VariantValue::UInt32(_) => VariantTypeId::UInt32,
            VariantValue::Int64(_) => VariantTypeId::Int64,
            VariantValue::UInt64(_) => VariantTypeId::UInt64,
            VariantValue::Real32(_) => VariantTypeId::Real32,
            VariantValue::Real64(_) => VariantTypeId::Real64,
            VariantValue::String(_) => VariantTypeId::String,
            VariantValue::Array(_) => VariantTypeId::Array,
            VariantValue::Object(_) => VariantTypeId::Object,
        }
    }

    /// Returns the underlying value as a boolean, but only if stored
    /// as a boolean. Otherwise, returns none.
    pub fn to_bool(&self) -> Result<bool, anyhow::Error> {
        match *self {
            VariantValue::Bit(my_bit) => {
                return Ok(my_bit);
            }
            _ => {
                return Err(anyhow!("Cannot convert {} to bool!", *self));
            }
        }
    }

    pub fn to_byte(&self) -> Result<u8, anyhow::Error> {
        match *self {
            VariantValue::Byte(item) => {
                return Ok(item);
            }
            _ => {
                return Err(anyhow!("Cannot convert {} to byte!", *self));
            }
        }
    }

    pub fn to_sbyte(&self) -> Result<i8, anyhow::Error> {
        match *self {
            VariantValue::SByte(item) => {
                return Ok(item);
            }
            _ => {
                return Err(anyhow!("Cannot convert {} to sbyte!", *self));
            }
        }
    }

    pub fn to_int16(&self) -> Result<i16, anyhow::Error> {
        match *self {
            VariantValue::Int16(item) => {
                return Ok(item);
            }
            _ => {
                return Err(anyhow!("Cannot convert {} to int16!", *self));
            }
        }
    }

    pub fn to_uint16(&self) -> Result<u16, anyhow::Error> {
        match *self {
            VariantValue::UInt16(item) => {
                return Ok(item);
            }
            _ => {
                return Err(anyhow!("Cannot convert {} to uint16!", *self));
            }
        }
    }

    /// Converts the underlying type to an int32, but only if the underlying type is
    /// and int32. Otherwise, returns None.
    pub fn to_int32(&self) -> Result<i32, anyhow::Error> {
        match *self {
            VariantValue::Int32(item) => {
                return Ok(item);
            }
            _ => {
                return Err(anyhow!("Cannot convert {} to int32!", *self));
            }
        }
        // match self {
        //     VariantValue::Int32(v) => Ok(*v),
        //     VariantValue::Int16(v) => Ok(*v as i32),
        //     VariantValue::UInt16(v) => Ok(*v as i32),
        //     VariantValue::Byte(v) => Ok(*v as i32),
        //     VariantValue::SByte(v) => Ok(*v as i32),
        //     VariantValue::Int64(v) => Err(anyhow::anyhow!("Value out of range for i32")),
        //     VariantValue::UInt32(v) => Ok(*v as i32),
        //     VariantValue::UInt64(v) => Err(anyhow::anyhow!("Value out of range for i32")),
        //     VariantValue::Real32(v) => Err(anyhow::anyhow!("Cannot convert f32 to i32")),
        //     VariantValue::Real64(v) => Err(anyhow::anyhow!("Cannot convert f64 to i32")),
        //     _ => Err(anyhow::anyhow!("Cannot convert {} to i32!", self.get_type_id())),
        // }
    }

    pub fn to_uint32(&self) -> Result<u32, anyhow::Error> {
        match *self {
            VariantValue::UInt32(item) => {
                return Ok(item);
            }
            _ => {
                return Err(anyhow!("Cannot convert {} to uint32!", *self));
            }
        }
    }

    pub fn to_int64(&self) -> Result<i64, anyhow::Error> {
        match *self {
            VariantValue::Int64(item) => {
                return Ok(item);
            }
            _ => {
                return Err(anyhow!("Cannot convert {} to int64!", *self));
            }
        }
    }

    pub fn to_uint64(&self) -> Result<u64, anyhow::Error> {
        match *self {
            VariantValue::UInt64(item) => {
                return Ok(item);
            }
            _ => {
                return Err(anyhow!("Cannot convert {} to uint64!", *self));
            }
        }
    }

    pub fn to_real32(&self) -> Result<f32, anyhow::Error> {
        match *self {
            VariantValue::Real32(item) => {
                return Ok(item);
            }
            _ => {
                return Err(anyhow!("Cannot convert {} to real32!", *self));
            }
        }
    }

    pub fn to_real64(&self) -> Result<f64, anyhow::Error> {
        match *self {
            VariantValue::Real64(item) => {
                return Ok(item);
            }
            _ => {
                return Err(anyhow!("Cannot convert {} to real64!", *self));
            }
        }
    }

    /// Flatten into a serde_json::Value for easy integration and transmission via
    /// other libraries.
    pub fn to_json(&self) -> Result<serde_json::Value, anyhow::Error> {
        match &*self {
            VariantValue::Null => {
                return Err(anyhow!("Cannot serialize a NULL value!"));
            }
            VariantValue::Bit(s) => {
                return Ok(serde_json::json!(s));
            }
            VariantValue::Byte(s) => {
                return Ok(serde_json::json!(s));
            }
            VariantValue::SByte(s) => {
                return Ok(serde_json::json!(s));
            }
            VariantValue::Int16(s) => {
                return Ok(serde_json::json!(s));
            }
            VariantValue::UInt16(s) => {
                return Ok(serde_json::json!(s));
            }
            VariantValue::Int32(s) => {
                return Ok(serde_json::json!(s));
            }
            VariantValue::UInt32(s) => {
                return Ok(serde_json::json!(s));
            }
            VariantValue::Int64(s) => {
                return Ok(serde_json::json!(s));
            }
            VariantValue::UInt64(s) => {
                return Ok(serde_json::json!(s));
            }
            VariantValue::Real32(s) => {
                return Ok(serde_json::json!(s));
            }
            VariantValue::Real64(s) => {
                return Ok(serde_json::json!(s));
            }
            VariantValue::String(s) => {
                return Ok(serde_json::json!(s));
            }
            VariantValue::Array(elements) => {
                let json_elements: Result<Vec<_>, _> =
                    elements.iter().map(|elem| elem.to_json()).collect();
                json_elements.map(serde_json::Value::Array)
            }
            VariantValue::Object(map) => {
                let mut json_map = serde_json::Map::new();
                for (key, value) in map.iter() {
                    json_map.insert(key.clone(), value.to_json()?);
                }
                Ok(serde_json::Value::Object(json_map))
            }
        }
    }

    /// Returns a reference to the inner Vec if this is an Array variant, otherwise None.
    pub fn to_array(&self) -> Result<&Vec<VariantValue>, anyhow::Error> {
        if let VariantValue::Array(vec) = self {
            Ok(vec)
        } else {
            return Err(anyhow!("Cannot convert to array."));
        }
    }

    /// Returns the value as a boolean, attempting to convert if the underlying
    /// value does is not the same type. Returns Error if conversion not possible.
    pub fn convert_to_bool(&self) -> Result<bool, anyhow::Error> {
        match self {
            VariantValue::Bit(v) => Ok(*v),
            VariantValue::Int32(v) => Ok(*v != 0),
            VariantValue::Int16(v) => Ok(*v != 0),
            VariantValue::UInt16(v) => Ok(*v != 0),
            VariantValue::Byte(v) => Ok(*v != 0),
            VariantValue::SByte(v) => Ok(*v != 0),
            VariantValue::Int64(v) => Ok(*v != 0),
            VariantValue::UInt32(v) => Ok(*v != 0),
            VariantValue::UInt64(v) => Ok(*v != 0),
            _ => Err(anyhow::anyhow!(
                "Cannot convert {} to bool!",
                self.get_type_id()
            )),
        }
    }

    /// Returns the value as a byte, attempting to convert if the underlying
    /// value does is not the same type. Returns Error if conversion not possible.
    pub fn convert_to_byte(&self) -> Result<u8, anyhow::Error> {
        match self {
            VariantValue::Bit(v) => Ok(*v as u8),
            VariantValue::Byte(v) => Ok(*v),
            VariantValue::SByte(v) => Ok(*v as u8),
            _ => Err(anyhow::anyhow!(
                "Cannot convert {} to Byte!",
                self.get_type_id()
            )),
        }
    }

    /// Returns the value as a signed byte, attempting to convert if the underlying
    /// value does is not the same type. Returns Error if conversion not possible.
    pub fn convert_to_sbyte(&self) -> Result<i8, anyhow::Error> {
        match self {
            VariantValue::Bit(v) => Ok(*v as i8),
            VariantValue::Byte(v) => Ok(*v as i8),
            VariantValue::SByte(v) => Ok(*v),
            _ => Err(anyhow::anyhow!(
                "Cannot convert {} to SByte!",
                self.get_type_id()
            )),
        }
    }

    /// Returns the value as an Int16, attempting to convert if the underlying
    /// value does is not the same type. Returns Error if conversion not possible.
    pub fn convert_to_int16(&self) -> Result<i16, anyhow::Error> {
        match self {
            VariantValue::Int16(v) => Ok(*v),
            VariantValue::UInt16(v) => Ok(*v as i16),
            VariantValue::Byte(v) => Ok(*v as i16),
            VariantValue::SByte(v) => Ok(*v as i16),
            _ => Err(anyhow::anyhow!(
                "Cannot convert {} to Int16!",
                self.get_type_id()
            )),
        }
    }

    /// Returns the value as a UInt16, attempting to convert if the underlying
    /// value does is not the same type. Returns Error if conversion not possible.
    pub fn convert_to_uint16(&self) -> Result<u16, anyhow::Error> {
        match self {
            VariantValue::Int16(v) => Ok(*v as u16),
            VariantValue::UInt16(v) => Ok(*v),
            VariantValue::Byte(v) => Ok(*v as u16),
            VariantValue::SByte(v) => Ok(*v as u16),
            _ => Err(anyhow::anyhow!(
                "Cannot convert {} to UInt16!",
                self.get_type_id()
            )),
        }
    }

    /// Returns the value as an Int32, attempting to convert if the underlying
    /// value does is not the same type. Returns Error if conversion not possible.
    pub fn convert_to_int32(&self) -> Result<i32, anyhow::Error> {
        match self {
            VariantValue::Int32(v) => Ok(*v),
            VariantValue::Int16(v) => Ok(*v as i32),
            VariantValue::UInt16(v) => Ok(*v as i32),
            VariantValue::Byte(v) => Ok(*v as i32),
            VariantValue::SByte(v) => Ok(*v as i32),
            VariantValue::UInt32(v) => Ok(*v as i32),
            _ => Err(anyhow::anyhow!(
                "Cannot convert {} to Int32!",
                self.get_type_id()
            )),
        }
    }

    /// Returns the value as a UInt32, attempting to convert if the underlying
    /// value does is not the same type. Returns Error if conversion not possible.    
    pub fn convert_to_uint32(&self) -> Result<u32, anyhow::Error> {
        match self {
            VariantValue::Int32(v) => Ok(*v as u32),
            VariantValue::Int16(v) => Ok(*v as u32),
            VariantValue::UInt16(v) => Ok(*v as u32),
            VariantValue::Byte(v) => Ok(*v as u32),
            VariantValue::SByte(v) => Ok(*v as u32),
            VariantValue::UInt32(v) => Ok(*v),
            _ => Err(anyhow::anyhow!(
                "Cannot convert {} to UInt32!",
                self.get_type_id()
            )),
        }
    }

    /// Returns the value as an Int64, attempting to convert if the underlying
    /// value does is not the same type. Returns Error if conversion not possible.      
    pub fn convert_to_int64(&self) -> Result<i64, anyhow::Error> {
        match self {
            VariantValue::Int32(v) => Ok(*v as i64),
            VariantValue::Int16(v) => Ok(*v as i64),
            VariantValue::UInt16(v) => Ok(*v as i64),
            VariantValue::Byte(v) => Ok(*v as i64),
            VariantValue::SByte(v) => Ok(*v as i64),
            VariantValue::UInt32(v) => Ok(*v as i64),
            VariantValue::Int64(v) => Ok(*v),
            VariantValue::UInt64(v) => Ok(*v as i64),
            _ => Err(anyhow::anyhow!(
                "Cannot convert {} to Int64!",
                self.get_type_id()
            )),
        }
    }

    /// Returns the value as a UInt64, attempting to convert if the underlying
    /// value does is not the same type. Returns Error if conversion not possible.      
    pub fn convert_to_uint64(&self) -> Result<u64, anyhow::Error> {
        match self {
            VariantValue::Int32(v) => Ok(*v as u64),
            VariantValue::Int16(v) => Ok(*v as u64),
            VariantValue::UInt16(v) => Ok(*v as u64),
            VariantValue::Byte(v) => Ok(*v as u64),
            VariantValue::SByte(v) => Ok(*v as u64),
            VariantValue::UInt32(v) => Ok(*v as u64),
            VariantValue::Int64(v) => Ok(*v as u64),
            VariantValue::UInt64(v) => Ok(*v),
            _ => Err(anyhow::anyhow!(
                "Cannot convert {} to UInt64!",
                self.get_type_id()
            )),
        }
    }

    /// Returns the value as a Real32, attempting to convert if the underlying
    /// value does is not the same type. Returns Error if conversion not possible.         
    pub fn convert_to_real32(&self) -> Result<f32, anyhow::Error> {
        match self {
            VariantValue::Int32(v) => Ok(*v as f32),
            VariantValue::Int16(v) => Ok(*v as f32),
            VariantValue::UInt16(v) => Ok(*v as f32),
            VariantValue::Byte(v) => Ok(*v as f32),
            VariantValue::SByte(v) => Ok(*v as f32),
            VariantValue::UInt32(v) => Ok(*v as f32),
            _ => Err(anyhow::anyhow!(
                "Cannot convert {} to Real32!",
                self.get_type_id()
            )),
        }
    }

    /// Returns the value as a Real64, attempting to convert if the underlying
    /// value does is not the same type. Returns Error if conversion not possible.       
    pub fn convert_to_real64(&self) -> Result<f64, anyhow::Error> {
        match self {
            VariantValue::Int32(v) => Ok(*v as f64),
            VariantValue::Int16(v) => Ok(*v as f64),
            VariantValue::UInt16(v) => Ok(*v as f64),
            VariantValue::Byte(v) => Ok(*v as f64),
            VariantValue::SByte(v) => Ok(*v as f64),
            VariantValue::UInt32(v) => Ok(*v as f64),
            VariantValue::Int64(v) => Ok(*v as f64),
            VariantValue::UInt64(v) => Ok(*v as f64),
            VariantValue::Real32(v) => Ok(*v as f64),
            VariantValue::Real64(v) => Ok(*v),
            _ => Err(anyhow::anyhow!(
                "Cannot convert {} to Real64!",
                self.get_type_id()
            )),
        }
    }

    /// Returns true if the VariantValue contains a numeric type.
    pub fn is_numeric(&self) -> bool {
        return matches!(
            self,
            VariantValue::Byte(_)
                | VariantValue::SByte(_)
                | VariantValue::Int16(_)
                | VariantValue::UInt16(_)
                | VariantValue::Int32(_)
                | VariantValue::UInt32(_)
                | VariantValue::Int64(_)
                | VariantValue::UInt64(_)
                | VariantValue::Real32(_)
                | VariantValue::Real64(_)
        );
    }

    /// Utility function for converting the underlying value to
    /// a byte stream. Note that the derived type must be compatible
    /// with serde::Serialize.
    fn serialize<T>(value: &T) -> Result<Vec<u8>, anyhow::Error>
    where
        T: Serialize,
    {
        match postcard::to_allocvec(&value) {
            Ok(bytes) => {
                return Ok(bytes);
            }
            Err(err) => {
                return Err(anyhow!("Error serializing: {}", err));
            }
        }
    }

    /// Serialize the value into a byte stream that can be transmitted
    /// over a connection.
    pub fn get_bytes(&self) -> Result<Vec<u8>, anyhow::Error> {
        match &*self {
            VariantValue::Null => {
                return Err(anyhow!("Cannot serialize a NULL value!"));
            }
            VariantValue::Bit(s) => {
                return Self::serialize(&s);
            }
            VariantValue::Byte(s) => {
                return Self::serialize(&s);
            }
            VariantValue::SByte(s) => {
                return Self::serialize(&s);
            }
            VariantValue::Int16(s) => {
                return Self::serialize(&s);
            }
            VariantValue::UInt16(s) => {
                return Self::serialize(&s);
            }
            VariantValue::Int32(s) => {
                return Self::serialize(&s);
            }
            VariantValue::UInt32(s) => {
                return Self::serialize(&s);
            }
            VariantValue::Int64(s) => {
                return Self::serialize(&s);
            }
            VariantValue::UInt64(s) => {
                return Self::serialize(&s);
            }
            VariantValue::Real32(s) => {
                return Self::serialize(&s);
            }
            VariantValue::Real64(s) => {
                return Self::serialize(&s);
            }
            VariantValue::String(s) => {
                return Self::serialize(&s);
            }
            VariantValue::Array(elements) => {
                return Self::serialize(elements);
            }
            VariantValue::Object(map) => {
                return Self::serialize(map);
            }
        }
    }
}

impl From<()> for VariantValue {
    fn from(_: ()) -> Self {
        VariantValue::Null
    }
}

impl From<bool> for VariantValue {
    fn from(v: bool) -> Self {
        VariantValue::Bit(v)
    }
}

impl From<u8> for VariantValue {
    fn from(v: u8) -> Self {
        VariantValue::Byte(v)
    }
}

impl From<i8> for VariantValue {
    fn from(v: i8) -> Self {
        VariantValue::SByte(v)
    }
}

impl From<i16> for VariantValue {
    fn from(v: i16) -> Self {
        VariantValue::Int16(v)
    }
}

impl From<u16> for VariantValue {
    fn from(v: u16) -> Self {
        VariantValue::UInt16(v)
    }
}

impl From<i32> for VariantValue {
    fn from(v: i32) -> Self {
        VariantValue::Int32(v)
    }
}

impl From<u32> for VariantValue {
    fn from(v: u32) -> Self {
        VariantValue::UInt32(v)
    }
}

impl From<i64> for VariantValue {
    fn from(v: i64) -> Self {
        VariantValue::Int64(v)
    }
}

impl From<u64> for VariantValue {
    fn from(v: u64) -> Self {
        VariantValue::UInt64(v)
    }
}

impl From<f32> for VariantValue {
    fn from(v: f32) -> Self {
        VariantValue::Real32(v)
    }
}

impl From<f64> for VariantValue {
    fn from(v: f64) -> Self {
        VariantValue::Real64(v)
    }
}

impl<'a> From<&'a str> for VariantValue {
    fn from(v: &'a str) -> Self {
        VariantValue::String(String::from(v))
    }
}

impl From<String> for VariantValue {
    fn from(v: String) -> Self {
        VariantValue::String(String::from(v))
    }
}

impl From<Vec<i32>> for VariantValue {
    fn from(v: Vec<i32>) -> Self {
        let mut ret = Vec::<VariantValue>::new();

        for item in v {
            ret.push(VariantValue::from(item));
        }

        return VariantValue::Array(ret);
    }
}

impl From<&[i32]> for VariantValue {
    fn from(v: &[i32]) -> Self {
        let mut ret = Vec::<VariantValue>::new();

        for item in v {
            ret.push(VariantValue::from(*item));
        }

        return VariantValue::Array(ret);
    }
}

// impl From<Vec<u8>> for VariantValue {
//     fn from(type_id : VariantTypeId, bytes : Vec<u8>) -> Self {
//         VariantValue::String(String::from(v))
//     }
// }

fn deserialize_primative<'a, T>(stream: &'a Vec<u8>) -> Result<T, anyhow::Error>
where
    T: Deserialize<'a>,
{
    match postcard::from_bytes::<T>(stream) {
        Ok(ret) => {
            return Ok(ret);
        }
        Err(err) => {
            return Err(anyhow!("deserialize_primative failed: {}", err));
        }
    }
}

pub fn from_bytes(type_id: VariantTypeId, bytes: &Vec<u8>) -> Result<VariantValue, anyhow::Error> {
    match &type_id {
        VariantTypeId::Null => {
            return Ok(VariantValue::Null);
        }
        VariantTypeId::Bit => match deserialize_primative::<bool>(&bytes) {
            Ok(ret) => {
                return Ok(VariantValue::Bit(ret));
            }
            Err(err) => {
                return Err(anyhow!("from_bytes failed: {}", err));
            }
        },
        VariantTypeId::Byte => match deserialize_primative::<u8>(&bytes) {
            Ok(ret) => {
                return Ok(VariantValue::Byte(ret));
            }
            Err(err) => {
                return Err(anyhow!("from_bytes failed: {}", err));
            }
        },
        VariantTypeId::SByte => match deserialize_primative::<i8>(&bytes) {
            Ok(ret) => {
                return Ok(VariantValue::SByte(ret));
            }
            Err(err) => {
                return Err(anyhow!("from_bytes failed: {}", err));
            }
        },
        VariantTypeId::Int16 => match deserialize_primative::<i16>(&bytes) {
            Ok(ret) => {
                return Ok(VariantValue::Int16(ret));
            }
            Err(err) => {
                return Err(anyhow!("from_bytes failed: {}", err));
            }
        },
        VariantTypeId::UInt16 => match deserialize_primative::<u16>(&bytes) {
            Ok(ret) => {
                return Ok(VariantValue::UInt16(ret));
            }
            Err(err) => {
                return Err(anyhow!("from_bytes failed: {}", err));
            }
        },
        VariantTypeId::Int32 => match deserialize_primative::<i32>(&bytes) {
            Ok(ret) => {
                return Ok(VariantValue::Int32(ret));
            }
            Err(err) => {
                return Err(anyhow!("from_bytes failed: {}", err));
            }
        },
        VariantTypeId::UInt32 => match deserialize_primative::<u32>(&bytes) {
            Ok(ret) => {
                return Ok(VariantValue::UInt32(ret));
            }
            Err(err) => {
                return Err(anyhow!("from_bytes failed: {}", err));
            }
        },
        VariantTypeId::Int64 => match deserialize_primative::<i64>(&bytes) {
            Ok(ret) => {
                return Ok(VariantValue::Int64(ret));
            }
            Err(err) => {
                return Err(anyhow!("from_bytes failed: {}", err));
            }
        },
        VariantTypeId::UInt64 => match deserialize_primative::<u64>(&bytes) {
            Ok(ret) => {
                return Ok(VariantValue::UInt64(ret));
            }
            Err(err) => {
                return Err(anyhow!("from_bytes failed: {}", err));
            }
        },
        VariantTypeId::Real32 => match deserialize_primative::<f32>(&bytes) {
            Ok(ret) => {
                return Ok(VariantValue::Real32(ret));
            }
            Err(err) => {
                return Err(anyhow!("from_bytes failed: {}", err));
            }
        },
        VariantTypeId::Real64 => match deserialize_primative::<f64>(&bytes) {
            Ok(ret) => {
                return Ok(VariantValue::Real64(ret));
            }
            Err(err) => {
                return Err(anyhow!("from_bytes failed: {}", err));
            }
        },
        VariantTypeId::String => match deserialize_primative::<String>(&bytes) {
            Ok(ret) => {
                return Ok(VariantValue::String(ret));
            }
            Err(err) => {
                return Err(anyhow!("from_bytes failed: {}", err));
            }
        },
        VariantTypeId::Array => deserialize_primative::<Vec<VariantValue>>(bytes)
            .map(VariantValue::Array)
            .map_err(|e| e.context("Deserializing an Array failed")),
        VariantTypeId::Object => deserialize_primative::<IndexMap<String, VariantValue>>(bytes)
            .map(|obj_map| VariantValue::Object(Box::new(obj_map)))
            .map_err(|e| e.context("Deserializing an Object failed")),
    }
}

/// Implement this Display trait for Variant, allowing it to be printed
/// easily in println! or log statement.
impl fmt::Display for VariantValue {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            VariantValue::Null => write!(f, "<NULL>"),
            VariantValue::Bit(v) => write!(f, "{}", v),
            VariantValue::Byte(v) => write!(f, "{}", v),
            VariantValue::SByte(v) => write!(f, "{}", v),
            VariantValue::Int16(v) => write!(f, "{}", v),
            VariantValue::UInt16(v) => write!(f, "{}", v),
            VariantValue::Int32(v) => write!(f, "{}", v),
            VariantValue::UInt32(v) => write!(f, "{}", v),
            VariantValue::Int64(v) => write!(f, "{}", v),
            VariantValue::UInt64(v) => write!(f, "{}", v),
            VariantValue::Real32(v) => write!(f, "{}", v),
            VariantValue::Real64(v) => write!(f, "{}", v),
            VariantValue::String(v) => write!(f, "{}", v),

            VariantValue::Array(elements) => {
                let elems_str = elements
                    .iter()
                    .map(|elem| format!("{}", elem))
                    .collect::<Vec<String>>()
                    .join(", ");
                write!(f, "[{}]", elems_str)
            }
            VariantValue::Object(map) => {
                let mut pairs = vec![];
                for (key, value) in map.iter() {
                    let pair = format!("\"{}\": {}", key, value);
                    pairs.push(pair);
                }
                let obj_str = pairs.join(", ");
                write!(f, "{{{}}}", obj_str)
            }
        }
    }
}

#[test]
pub fn test_variant() {
    let mut tst = VariantValue::Bit(true);

    assert_ne!(tst.is_null(), true);
    assert!(matches!(tst.to_bool(), Ok(true)));

    assert!(matches!(tst.to_real32(), Err(_err)));

    trace!("tst is awesome {:?}", tst);

    tst = VariantValue::from(12);

    trace!("Updated tst using from: {:?}", tst);

    // VariantValue doesn't wrangle types.
    // This should be true.
    assert!(matches!(tst.to_int32(), Ok(12)));

    // This should not be true.
    assert!(!matches!(tst.to_int16(), Ok(12)));

    match tst.get_bytes() {
        Ok(bytes) => {
            for item in &bytes {
                trace!("\t byte [{}]", item);
            }

            //assert_eq!(bytes.len(), std::mem::size_of::<u32>().try_into().unwrap());
            assert_eq!(bytes[0], 12);

            let new_var = from_bytes(VariantTypeId::Int32, &bytes).unwrap();

            assert!(matches!(new_var.to_int32(), Ok(12)));
        }
        _ => {
            warn!("Failed to serialize bytes!");
            panic!();
        }
    }

    // Initialize an empty IndexMap.
    let mut map: IndexMap<String, VariantValue> = IndexMap::new();

    // Add some data to the map.
    // For example, let's add a string and an integer.
    map.insert(
        "key1".to_string(),
        VariantValue::String("value1".to_string()),
    );
    map.insert("key2".to_string(), VariantValue::Int32(42));

    // Now, create a VariantValue::Object with this map.
    let mut var_obj = VariantValue::Object(Box::new(map));

    // To demonstrate accessing and modifying the object,
    // let's add another value to the object.

    // Access the IndexMap directly from the VariantValue::Object variant.
    // Note: You need to do pattern matching or use if let / match statements
    // for safer access in real-world scenarios. This example assumes the direct access for simplicity.
    if let VariantValue::Object(ref mut boxed_map) = var_obj {
        // Insert a new key-value pair.
        boxed_map.insert("key3".to_string(), VariantValue::Real64(3.14));
    }

    let obj_out = format!("{}", var_obj);

    // Test that object maintains order
    assert_eq!(obj_out, "{\"key1\": value1, \"key2\": 42, \"key3\": 3.14}");
}
