use base64::Engine;
use base64::engine::general_purpose::STANDARD;
use icu::calendar::Date as IcuDate;
use icu::datetime::DateTimeFormatter;
use icu::datetime::fieldsets;
use icu::decimal::DecimalFormatter;
use icu::decimal::input::Decimal as IcuDecimal;
use icu::locale::Locale as IcuLocale;
use icu::time::DateTime as IcuDateTime;
use icu::time::Time as IcuTime;
use indexmap::IndexMap;
use jiff::civil::{Date, DateTime, Time};
use jiff_icu::ConvertFrom;
use rust_decimal::Decimal;
use serde::{Serialize, Serializer};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::str::FromStr;
use uuid::Uuid;

/// Caches ICU formatters for a given locale to avoid repeated construction.
#[derive(Debug)]
pub struct ValueFormatter {
    locale_name: String,
    decimal_formatter: DecimalFormatter,
    date_formatter: DateTimeFormatter<fieldsets::YMD>,
    time_formatter: DateTimeFormatter<fieldsets::T>,
    datetime_formatter: DateTimeFormatter<fieldsets::YMDT>,
}

impl ValueFormatter {
    /// Create a new `ValueFormatter` for the given locale string (e.g. "en", "de", "fr").
    /// Falls back to "en" if the locale cannot be parsed.
    pub fn new(locale: &str) -> Self {
        let icu_locale = IcuLocale::from_str(locale)
            .unwrap_or_else(|_| IcuLocale::from_str("en").expect("en locale should always parse"));
        let locale_name = locale.to_string();

        let decimal_formatter = DecimalFormatter::try_new((&icu_locale).into(), Default::default())
            .expect("decimal formatter should be created");
        let date_formatter =
            DateTimeFormatter::try_new((&icu_locale).into(), fieldsets::YMD::medium())
                .expect("date formatter should be created");
        let time_formatter =
            DateTimeFormatter::try_new((&icu_locale).into(), fieldsets::T::medium())
                .expect("time formatter should be created");
        let datetime_formatter =
            DateTimeFormatter::try_new((&icu_locale).into(), fieldsets::YMDT::medium())
                .expect("datetime formatter should be created");

        Self {
            locale_name,
            decimal_formatter,
            date_formatter,
            time_formatter,
            datetime_formatter,
        }
    }

    /// Get the locale name string.
    #[must_use]
    pub fn locale_name(&self) -> &str {
        &self.locale_name
    }

    /// Format an integer using the cached decimal formatter.
    #[must_use]
    pub fn format_integer<T: Into<IcuDecimal>>(&self, value: T) -> String {
        self.decimal_formatter.format_to_string(&value.into())
    }

    /// Format a jiff Date using the cached date formatter.
    #[must_use]
    pub fn format_date(&self, value: &Date) -> String {
        let icu_date = IcuDate::convert_from(*value);
        self.date_formatter.format(&icu_date).to_string()
    }

    /// Format a jiff Time using the cached time formatter.
    #[must_use]
    pub fn format_time(&self, value: &Time) -> String {
        let icu_time = IcuTime::convert_from(*value);
        self.time_formatter.format(&icu_time).to_string()
    }

    /// Format a jiff DateTime using the cached datetime formatter.
    #[must_use]
    pub fn format_datetime(&self, value: &DateTime) -> String {
        let icu_dt = IcuDateTime::convert_from(*value);
        self.datetime_formatter.format(&icu_dt).to_string()
    }
}

#[derive(Clone, Debug)]
pub enum Value {
    Null,
    Bool(bool),
    Bytes(Vec<u8>),
    I8(i8),
    I16(i16),
    I32(i32),
    I64(i64),
    I128(i128),
    U8(u8),
    U16(u16),
    U32(u32),
    U64(u64),
    U128(u128),
    F32(f32),
    F64(f64),
    String(String),
    Decimal(Decimal),
    Date(Date),
    Time(Time),
    DateTime(DateTime),
    Uuid(Uuid),
    Array(Vec<Value>),
    Map(IndexMap<Value, Value>),
}

impl Value {
    #[must_use]
    pub fn to_formatted_string(&self, formatter: &ValueFormatter) -> String {
        match self {
            Value::Null => "null".to_string(),
            Value::Bool(value) => value.to_string(),
            Value::Bytes(bytes) => STANDARD.encode(bytes),
            Value::I8(value) => formatter.format_integer(*value),
            Value::I16(value) => formatter.format_integer(*value),
            Value::I32(value) => formatter.format_integer(*value),
            Value::I64(value) => formatter.format_integer(*value),
            Value::I128(value) => formatter.format_integer(*value),
            Value::U8(value) => formatter.format_integer(*value),
            Value::U16(value) => formatter.format_integer(*value),
            Value::U32(value) => formatter.format_integer(*value),
            Value::U64(value) => formatter.format_integer(*value),
            Value::U128(value) => formatter.format_integer(*value),
            Value::F32(value) => value.to_string(),
            Value::F64(value) => value.to_string(),
            Value::String(value) => value.to_string(),
            Value::Decimal(value) => value.to_string(),
            Value::Date(value) => {
                // TODO: add localized date formatting
                // formatter.format_date(value)
                value.to_string()
            }
            Value::Time(value) => {
                // TODO: add localized time formatting
                // formatter.format_time(value)
                value.to_string()
            }
            Value::DateTime(value) => {
                // TODO: add localized datetime formatting
                // formatter.format_datetime(value)
                value.to_string()
            }
            Value::Uuid(value) => value.to_string(),
            Value::Array(value) => {
                let locale = formatter.locale_name();
                let list_delimiter = t!("list_delimiter", locale = locale).to_string();
                value
                    .iter()
                    .map(|value| value.to_formatted_string(formatter))
                    .collect::<Vec<String>>()
                    .join(list_delimiter.as_str())
            }
            Value::Map(value) => {
                let locale = formatter.locale_name();
                let key_value_delimiter = t!("key_value_delimiter", locale = locale).to_string();
                let list_delimiter = t!("list_delimiter", locale = locale).to_string();
                value
                    .iter()
                    .map(|(key, value)| {
                        format!(
                            "{}{}{}",
                            key.to_formatted_string(formatter),
                            key_value_delimiter,
                            value.to_formatted_string(formatter)
                        )
                    })
                    .collect::<Vec<String>>()
                    .join(list_delimiter.as_str())
            }
        }
    }

    #[must_use]
    pub fn is_null(&self) -> bool {
        matches!(self, Value::Null)
    }

    #[must_use]
    pub fn is_numeric(&self) -> bool {
        #[expect(clippy::match_like_matches_macro)]
        match self {
            Value::I8(_) | Value::I16(_) | Value::I32(_) | Value::I64(_) | Value::I128(_) => true,
            Value::U8(_) | Value::U16(_) | Value::U32(_) | Value::U64(_) | Value::U128(_) => true,
            Value::F32(_) | Value::F64(_) | Value::Decimal(_) => true,
            _ => false,
        }
    }
}

impl fmt::Display for Value {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let string_value = match self {
            Value::Null => "null".to_string(),
            Value::Bool(value) => value.to_string(),
            Value::Bytes(bytes) => STANDARD.encode(bytes),
            Value::I8(value) => value.to_string(),
            Value::I16(value) => value.to_string(),
            Value::I32(value) => value.to_string(),
            Value::I64(value) => value.to_string(),
            Value::I128(value) => value.to_string(),
            Value::U8(value) => value.to_string(),
            Value::U16(value) => value.to_string(),
            Value::U32(value) => value.to_string(),
            Value::U64(value) => value.to_string(),
            Value::U128(value) => value.to_string(),
            Value::F32(value) => value.to_string(),
            Value::F64(value) => value.to_string(),
            Value::String(value) => value.to_string(),
            Value::Decimal(value) => value.to_string(),
            Value::Date(value) => value.to_string(),
            Value::Time(value) => value.to_string(),
            Value::DateTime(value) => value.to_string(),
            Value::Uuid(value) => value.to_string(),
            Value::Array(value) => value
                .iter()
                .map(ToString::to_string)
                .collect::<Vec<String>>()
                .join(", "),
            Value::Map(value) => value
                .iter()
                .map(|(key, value)| format!("{key}={value}"))
                .collect::<Vec<String>>()
                .join(", "),
        };
        write!(f, "{string_value}")
    }
}

impl Eq for Value {}

impl Hash for Value {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match self {
            Value::Null => 0.hash(state),
            Value::Bool(value) => value.hash(state),
            Value::Bytes(value) => value.hash(state),
            Value::I8(value) => value.hash(state),
            Value::I16(value) => value.hash(state),
            Value::I32(value) => value.hash(state),
            Value::I64(value) => value.hash(state),
            Value::I128(value) => value.hash(state),
            Value::U8(value) => value.hash(state),
            Value::U16(value) => value.hash(state),
            Value::U32(value) => value.hash(state),
            Value::U64(value) => value.hash(state),
            Value::U128(value) => value.hash(state),
            Value::F32(value) => value.to_bits().hash(state),
            Value::F64(value) => value.to_bits().hash(state),
            Value::String(value) => value.hash(state),
            Value::Decimal(value) => value.hash(state),
            Value::Date(value) => value.hash(state),
            Value::Time(value) => value.hash(state),
            Value::DateTime(value) => value.hash(state),
            Value::Uuid(value) => value.hash(state),
            Value::Array(value) => value.hash(state),
            Value::Map(value) => {
                for (key, value) in value {
                    key.hash(state);
                    value.hash(state);
                }
            }
        }
    }
}

impl PartialEq for Value {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Value::Null, Value::Null) => true,
            (Value::Bool(a), Value::Bool(b)) => a == b,
            (Value::Bytes(a), Value::Bytes(b)) => a == b,
            (Value::I8(a), Value::I8(b)) => a == b,
            (Value::I16(a), Value::I16(b)) => a == b,
            (Value::I32(a), Value::I32(b)) => a == b,
            (Value::I64(a), Value::I64(b)) => a == b,
            (Value::I128(a), Value::I128(b)) => a == b,
            (Value::U8(a), Value::U8(b)) => a == b,
            (Value::U16(a), Value::U16(b)) => a == b,
            (Value::U32(a), Value::U32(b)) => a == b,
            (Value::U64(a), Value::U64(b)) => a == b,
            (Value::U128(a), Value::U128(b)) => a == b,
            (Value::F32(a), Value::F32(b)) => a == b,
            (Value::F64(a), Value::F64(b)) => a == b,
            (Value::String(a), Value::String(b)) => a == b,
            (Value::Decimal(a), Value::Decimal(b)) => a == b,
            (Value::Date(a), Value::Date(b)) => a == b,
            (Value::Time(a), Value::Time(b)) => a == b,
            (Value::DateTime(a), Value::DateTime(b)) => a == b,
            (Value::Uuid(a), Value::Uuid(b)) => a == b,
            (Value::Array(a), Value::Array(b)) => a == b,
            (Value::Map(a), Value::Map(b)) => {
                if a.len() != b.len() {
                    return false;
                }

                // Compare keys and values in an order-dependent manner
                a.iter()
                    .zip(b.iter())
                    .all(|((a_key, a_value), (b_key, b_value))| {
                        a_key == b_key && a_value == b_value
                    })
            }
            _ => false,
        }
    }
}

impl Serialize for Value {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match *self {
            Value::Null => serializer.serialize_none(),
            Value::Bool(value) => serializer.serialize_bool(value),
            Value::Bytes(ref value) => serializer.serialize_bytes(value),
            Value::I8(value) => serializer.serialize_i8(value),
            Value::I16(value) => serializer.serialize_i16(value),
            Value::I32(value) => serializer.serialize_i32(value),
            Value::I64(value) => serializer.serialize_i64(value),
            Value::I128(value) => serializer.serialize_str(&value.to_string()),
            Value::U8(value) => serializer.serialize_u8(value),
            Value::U16(value) => serializer.serialize_u16(value),
            Value::U32(value) => serializer.serialize_u32(value),
            Value::U64(value) => serializer.serialize_u64(value),
            Value::U128(value) => serializer.serialize_str(&value.to_string()),
            Value::F32(value) => serializer.serialize_f32(value),
            Value::F64(value) => serializer.serialize_f64(value),
            Value::String(ref value) => serializer.serialize_str(value),
            Value::Decimal(ref value) => serializer.serialize_str(&value.to_string()),
            Value::Date(value) => serializer.serialize_str(&value.to_string()),
            Value::Time(value) => serializer.serialize_str(&value.to_string()),
            Value::DateTime(value) => serializer.serialize_str(&value.to_string()),
            Value::Uuid(value) => serializer.serialize_str(&value.to_string()),
            Value::Array(ref value) => value.serialize(serializer),
            Value::Map(ref value) => value.serialize(serializer),
        }
    }
}

impl From<Option<Value>> for Value {
    fn from(value: Option<Value>) -> Self {
        value.unwrap_or(Value::Null)
    }
}

impl From<bool> for Value {
    fn from(value: bool) -> Self {
        Value::Bool(value)
    }
}

impl From<Vec<u8>> for Value {
    fn from(value: Vec<u8>) -> Self {
        Value::Bytes(value)
    }
}

impl From<i8> for Value {
    fn from(value: i8) -> Self {
        Value::I8(value)
    }
}

impl From<u8> for Value {
    fn from(value: u8) -> Self {
        Value::U8(value)
    }
}

impl From<i16> for Value {
    fn from(value: i16) -> Self {
        Value::I16(value)
    }
}

impl From<u16> for Value {
    fn from(value: u16) -> Self {
        Value::U16(value)
    }
}

impl From<i32> for Value {
    fn from(value: i32) -> Self {
        Value::I32(value)
    }
}

impl From<u32> for Value {
    fn from(value: u32) -> Self {
        Value::U32(value)
    }
}

impl From<i64> for Value {
    fn from(value: i64) -> Self {
        Value::I64(value)
    }
}

impl From<u64> for Value {
    fn from(value: u64) -> Self {
        Value::U64(value)
    }
}

impl From<isize> for Value {
    fn from(value: isize) -> Self {
        Value::I64(value as i64)
    }
}

impl From<usize> for Value {
    fn from(value: usize) -> Self {
        Value::U64(value as u64)
    }
}

impl From<i128> for Value {
    fn from(value: i128) -> Self {
        Value::I128(value)
    }
}

impl From<u128> for Value {
    fn from(value: u128) -> Self {
        Value::U128(value)
    }
}

impl From<f32> for Value {
    fn from(value: f32) -> Self {
        Value::F32(value)
    }
}

impl From<f64> for Value {
    fn from(value: f64) -> Self {
        Value::F64(value)
    }
}

impl From<&str> for Value {
    fn from(value: &str) -> Self {
        Value::String(value.to_string())
    }
}

impl From<String> for Value {
    fn from(value: String) -> Self {
        Value::String(value)
    }
}

impl From<Decimal> for Value {
    fn from(value: Decimal) -> Self {
        Value::Decimal(value)
    }
}

impl From<Date> for Value {
    fn from(value: Date) -> Self {
        Value::Date(value)
    }
}

impl From<Time> for Value {
    fn from(value: Time) -> Self {
        Value::Time(value)
    }
}

impl From<DateTime> for Value {
    fn from(value: DateTime) -> Self {
        Value::DateTime(value)
    }
}

impl From<Uuid> for Value {
    fn from(value: Uuid) -> Self {
        Value::Uuid(value)
    }
}

#[cfg(feature = "json")]
impl From<serde_json::Value> for Value {
    fn from(value: serde_json::Value) -> Self {
        match value {
            serde_json::Value::Null => Value::Null,
            serde_json::Value::Bool(value) => Value::Bool(value),
            serde_json::Value::Number(value) => {
                if let Some(value) = value.as_u64() {
                    Value::U64(value)
                } else if let Some(value) = value.as_i64() {
                    Value::I64(value)
                } else if let Some(value) = value.as_f64() {
                    Value::F64(value)
                } else {
                    Value::Null
                }
            }
            serde_json::Value::String(value) => Value::String(value),
            serde_json::Value::Array(value) => {
                let value = value.into_iter().map(Value::from).collect::<Vec<Value>>();
                Value::Array(value)
            }
            serde_json::Value::Object(value) => {
                let value = value
                    .into_iter()
                    .map(|(key, value)| (Value::String(key), Value::from(value)))
                    .collect::<IndexMap<Value, Value>>();
                Value::Map(value)
            }
        }
    }
}

impl From<Vec<Value>> for Value {
    fn from(value: Vec<Value>) -> Self {
        Value::Array(value)
    }
}

impl From<IndexMap<Value, Value>> for Value {
    fn from(value: IndexMap<Value, Value>) -> Self {
        Value::Map(value)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use anyhow::Result;
    use jiff::civil;
    use jiff::civil::DateTime;
    use serde_json::json;
    use std::str::FromStr;
    use uuid::Uuid;

    fn en_formatter() -> ValueFormatter {
        ValueFormatter::new("en")
    }

    #[test]
    fn test_null() {
        let fmt = en_formatter();
        assert!(Value::Null.is_null());
        assert!(!Value::Null.is_numeric());
        assert_eq!(Value::Null.to_formatted_string(&fmt), "null");
        assert_eq!(Value::Null.to_string(), "null");
        assert_eq!(json!(Value::Null), json!(serde_json::Value::Null));
    }

    #[test]
    fn test_bool() {
        let fmt = en_formatter();
        assert!(!Value::Bool(true).is_null());
        assert!(!Value::Bool(true).is_numeric());
        assert_eq!(Value::Bool(true).to_formatted_string(&fmt), "true");
        assert_eq!(Value::Bool(true).to_string(), "true");
        assert_eq!(json!(Value::Bool(true)), json!(true));
    }

    #[test]
    fn test_bytes() {
        let fmt = en_formatter();
        assert!(!Value::Bytes(vec![114, 117, 115, 116]).is_null());
        assert!(!Value::Bytes(vec![114, 117, 115, 116]).is_numeric());
        assert_eq!(
            Value::Bytes(vec![114, 117, 115, 116]).to_formatted_string(&fmt),
            "cnVzdA=="
        );
        assert_eq!(
            Value::Bytes(vec![114, 117, 115, 116]).to_string(),
            "cnVzdA=="
        );
        assert_eq!(
            json!(Value::Bytes(vec![114, 117, 115, 116])),
            serde_json::Value::Array(vec![
                serde_json::Value::Number(serde_json::Number::from(114)),
                serde_json::Value::Number(serde_json::Number::from(117)),
                serde_json::Value::Number(serde_json::Number::from(115)),
                serde_json::Value::Number(serde_json::Number::from(116))
            ])
        );
    }

    #[test]
    fn test_i8() {
        let fmt = en_formatter();
        assert!(!Value::I8(i8::MIN).is_null());
        assert!(Value::I8(i8::MIN).is_numeric());
        assert_eq!(Value::I8(i8::MIN).to_formatted_string(&fmt), "-128");
        assert_eq!(Value::I8(i8::MAX).to_formatted_string(&fmt), "127");

        assert_eq!(Value::I8(i8::MIN).to_string(), "-128");
        assert_eq!(Value::I8(i8::MAX).to_string(), "127");

        assert_eq!(json!(Value::I8(i8::MIN)), json!(i8::MIN));
        assert_eq!(json!(Value::I8(i8::MAX)), json!(i8::MAX));
    }

    #[test]
    fn test_i16() {
        let fmt = en_formatter();
        assert!(!Value::I16(i16::MIN).is_null());
        assert!(Value::I16(i16::MIN).is_numeric());
        assert_eq!(Value::I16(i16::MIN).to_formatted_string(&fmt), "-32,768");
        assert_eq!(Value::I16(i16::MAX).to_formatted_string(&fmt), "32,767");

        assert_eq!(Value::I16(i16::MIN).to_string(), "-32768");
        assert_eq!(Value::I16(i16::MAX).to_string(), "32767");

        assert_eq!(json!(Value::I16(i16::MIN)), json!(i16::MIN));
        assert_eq!(json!(Value::I16(i16::MAX)), json!(i16::MAX));
    }

    #[test]
    fn test_i32() {
        let fmt = en_formatter();
        assert!(!Value::I32(i32::MIN).is_null());
        assert!(Value::I32(i32::MIN).is_numeric());
        assert_eq!(
            Value::I32(i32::MIN).to_formatted_string(&fmt),
            "-2,147,483,648"
        );
        assert_eq!(
            Value::I32(i32::MAX).to_formatted_string(&fmt),
            "2,147,483,647"
        );

        assert_eq!(Value::I32(i32::MIN).to_string(), "-2147483648");
        assert_eq!(Value::I32(i32::MAX).to_string(), "2147483647");

        assert_eq!(json!(Value::I32(i32::MIN)), json!(i32::MIN));
        assert_eq!(json!(Value::I32(i32::MAX)), json!(i32::MAX));
    }

    #[test]
    fn test_i64() {
        let fmt = en_formatter();
        assert!(!Value::I64(i64::MIN).is_null());
        assert!(Value::I64(i64::MIN).is_numeric());
        assert_eq!(
            Value::I64(i64::MIN).to_formatted_string(&fmt),
            "-9,223,372,036,854,775,808"
        );
        assert_eq!(
            Value::I64(i64::MAX).to_formatted_string(&fmt),
            "9,223,372,036,854,775,807"
        );

        assert_eq!(Value::I64(i64::MIN).to_string(), "-9223372036854775808");
        assert_eq!(Value::I64(i64::MAX).to_string(), "9223372036854775807");

        assert_eq!(json!(Value::I64(i64::MIN)), json!(i64::MIN));
        assert_eq!(json!(Value::I64(i64::MAX)), json!(i64::MAX));
    }

    #[test]
    fn test_i128() {
        let fmt = en_formatter();
        assert!(!Value::I128(i128::MIN).is_null());
        assert!(Value::I128(i128::MIN).is_numeric());
        assert_eq!(
            Value::I128(i128::MIN).to_formatted_string(&fmt),
            "-170,141,183,460,469,231,731,687,303,715,884,105,728"
        );
        assert_eq!(
            Value::I128(i128::MAX).to_formatted_string(&fmt),
            "170,141,183,460,469,231,731,687,303,715,884,105,727"
        );

        assert_eq!(
            Value::I128(i128::MIN).to_string(),
            "-170141183460469231731687303715884105728"
        );
        assert_eq!(
            Value::I128(i128::MAX).to_string(),
            "170141183460469231731687303715884105727"
        );
    }

    #[test]
    fn test_u8() {
        let fmt = en_formatter();
        assert!(!Value::U8(u8::MAX).is_null());
        assert!(Value::U8(u8::MAX).is_numeric());
        assert_eq!(Value::U8(u8::MAX).to_formatted_string(&fmt), "255");
        assert_eq!(Value::U8(u8::MAX).to_string(), "255");
        assert_eq!(json!(Value::U8(u8::MAX)), json!(u8::MAX));
    }

    #[test]
    fn test_u16() {
        let fmt = en_formatter();
        assert!(!Value::U16(u16::MAX).is_null());
        assert!(Value::U16(u16::MAX).is_numeric());
        assert_eq!(Value::U16(u16::MAX).to_formatted_string(&fmt), "65,535");
        assert_eq!(Value::U16(u16::MAX).to_string(), "65535");
        assert_eq!(json!(Value::U16(u16::MAX)), json!(u16::MAX));
    }

    #[test]
    fn test_u32() {
        let fmt = en_formatter();
        assert!(!Value::U32(u32::MAX).is_null());
        assert!(Value::U32(u32::MAX).is_numeric());
        assert_eq!(
            Value::U32(u32::MAX).to_formatted_string(&fmt),
            "4,294,967,295"
        );
        assert_eq!(Value::U32(u32::MAX).to_string(), "4294967295");
        assert_eq!(json!(Value::U32(u32::MAX)), json!(u32::MAX));
    }

    #[test]
    fn test_u64() {
        let fmt = en_formatter();
        assert!(!Value::U64(u64::MAX).is_null());
        assert!(Value::U64(u64::MAX).is_numeric());
        assert_eq!(
            Value::U64(u64::MAX).to_formatted_string(&fmt),
            "18,446,744,073,709,551,615"
        );
        assert_eq!(Value::U64(u64::MAX).to_string(), "18446744073709551615");
        assert_eq!(json!(Value::U64(u64::MAX)), json!(u64::MAX));
    }

    #[test]
    fn test_u128() {
        let fmt = en_formatter();
        assert!(!Value::U128(u128::MAX).is_null());
        assert!(Value::U128(u128::MAX).is_numeric());
        assert_eq!(
            Value::U128(u128::MAX).to_formatted_string(&fmt),
            "340,282,366,920,938,463,463,374,607,431,768,211,455"
        );
        assert_eq!(
            Value::U128(u128::MAX).to_string(),
            "340282366920938463463374607431768211455"
        );
    }

    #[test]
    fn test_f32() {
        let fmt = en_formatter();
        assert!(!Value::F32(12_345.678).is_null());
        assert!(Value::F32(12_345.678).is_numeric());
        assert!(
            Value::F32(12_345.678)
                .to_formatted_string(&fmt)
                .starts_with("12345.")
        );
        assert!(Value::F32(12_345.678).to_string().starts_with("12345."));
        assert_eq!(json!(Value::F32(12_345.0)), json!(12_345.0));
    }

    #[test]
    fn test_f64() {
        let fmt = en_formatter();
        assert!(!Value::F64(12_345.678_90).is_null());
        assert!(Value::F64(12_345.678_90).is_numeric());
        assert!(
            Value::F64(12_345.678_90)
                .to_formatted_string(&fmt)
                .starts_with("12345.")
        );
        assert!(Value::F64(12_345.678_90).to_string().starts_with("12345."));
        assert_eq!(json!(Value::F64(12_345.678_90)), json!(12_345.678_90));
    }

    #[test]
    fn test_string() {
        let fmt = en_formatter();
        assert!(!Value::String("foo".to_string()).is_null());
        assert!(!Value::String("foo".to_string()).is_numeric());
        assert_eq!(
            Value::String("foo".to_string()).to_formatted_string(&fmt),
            "foo"
        );
        assert_eq!(Value::String("foo".to_string()).to_string(), "foo");
        assert_eq!(
            json!(Value::String("foo".to_string())),
            json!("foo".to_string())
        );
    }

    #[test]
    fn test_decimal() {
        let fmt = en_formatter();
        let decimal = rust_decimal::Decimal::from_str("12345.6789").expect("Invalid decimal");
        assert!(!Value::Decimal(decimal).is_null());
        assert!(Value::Decimal(decimal).is_numeric());
        assert_eq!(
            Value::Decimal(decimal).to_formatted_string(&fmt),
            "12345.6789"
        );
        assert_eq!(Value::Decimal(decimal).to_string(), "12345.6789");
        assert_eq!(
            json!(Value::Decimal(decimal)),
            json!("12345.6789".to_string())
        );
    }

    #[test]
    fn test_date() {
        let fmt = en_formatter();
        let date = jiff::civil::date(2000, 12, 31);
        assert!(!Value::Date(date).is_null());
        assert!(!Value::Date(date).is_numeric());
        assert_eq!(Value::Date(date).to_formatted_string(&fmt), "2000-12-31");
        assert_eq!(Value::Date(date).to_string(), "2000-12-31");
        assert_eq!(json!(Value::Date(date)), json!("2000-12-31"));
    }

    #[test]
    fn test_time() {
        let fmt = en_formatter();
        let time = jiff::civil::time(12, 13, 14, 15);
        assert!(!Value::Time(time).is_null());
        assert!(!Value::Time(time).is_numeric());
        assert_eq!(
            Value::Time(time).to_formatted_string(&fmt),
            "12:13:14.000000015"
        );
        assert_eq!(Value::Time(time).to_string(), "12:13:14.000000015");
        assert_eq!(json!(Value::Time(time)), json!("12:13:14.000000015"));
    }

    #[test]
    fn test_datetime() {
        let fmt = en_formatter();
        let date = civil::date(2000, 12, 31);
        let time = civil::time(12, 13, 14, 15);
        let date_time = DateTime::from_parts(date, time);
        assert!(!Value::DateTime(date_time).is_null());
        assert!(!Value::DateTime(date_time).is_numeric());
        assert_eq!(
            Value::DateTime(date_time).to_formatted_string(&fmt),
            "2000-12-31T12:13:14.000000015"
        );
        assert_eq!(
            Value::DateTime(date_time).to_string(),
            "2000-12-31T12:13:14.000000015"
        );
        assert_eq!(
            json!(Value::DateTime(date_time)),
            json!("2000-12-31T12:13:14.000000015")
        );
    }

    #[test]
    fn test_uuid() -> Result<()> {
        let fmt = en_formatter();
        let uuid = "acf5b3e3-4099-4f34-81c7-5803cbc87a2d";
        assert!(!Value::Uuid(Uuid::from_str(uuid)?).is_null());
        assert!(!Value::Uuid(Uuid::from_str(uuid)?).is_numeric());
        assert_eq!(
            Value::Uuid(Uuid::from_str(uuid)?).to_formatted_string(&fmt),
            uuid
        );
        assert_eq!(Value::Uuid(Uuid::from_str(uuid)?).to_string(), uuid);
        assert_eq!(json!(Value::Uuid(Uuid::from_str(uuid)?)), json!(uuid));
        Ok(())
    }

    #[test]
    fn test_array() -> Result<()> {
        let fmt = en_formatter();
        let array = vec![
            Value::Null,
            Value::Bool(true),
            Value::I8(1),
            Value::I16(2),
            Value::I32(3),
            Value::I64(12345),
            Value::I128(128),
            Value::U8(5),
            Value::U16(6),
            Value::U32(7),
            Value::U64(8),
            Value::U128(128),
            Value::F32(9.1),
            Value::F64(10.42),
            Value::String("foo".to_string()),
            Value::Date(jiff::civil::date(2000, 12, 31)),
            Value::Time(jiff::civil::time(12, 13, 14, 15)),
            Value::DateTime(jiff::civil::datetime(2000, 12, 31, 12, 13, 14, 15)),
            Value::Uuid(Uuid::from_str("acf5b3e3-4099-4f34-81c7-5803cbc87a2d")?),
        ];
        assert_eq!(
            Value::Array(array.clone()).to_formatted_string(&fmt),
            "null, true, 1, 2, 3, 12,345, 128, 5, 6, 7, 8, 128, 9.1, 10.42, foo, 2000-12-31, 12:13:14.000000015, 2000-12-31T12:13:14.000000015, acf5b3e3-4099-4f34-81c7-5803cbc87a2d"
        );
        assert_eq!(
            Value::Array(array.clone()).to_string(),
            "null, true, 1, 2, 3, 12345, 128, 5, 6, 7, 8, 128, 9.1, 10.42, foo, 2000-12-31, 12:13:14.000000015, 2000-12-31T12:13:14.000000015, acf5b3e3-4099-4f34-81c7-5803cbc87a2d"
        );
        assert_eq!(json!(Value::Array(array.clone())), json!(array.clone()));
        Ok(())
    }

    #[test]
    fn test_map() {
        let fmt = en_formatter();
        let mut map = IndexMap::new();
        map.insert(Value::String("foo".to_string()), Value::I32(123));
        map.insert(Value::String("bar".to_string()), Value::I32(456));
        map.insert(Value::String("baz".to_string()), Value::I32(789));
        assert_eq!(
            "foo=123, bar=456, baz=789",
            Value::Map(map.clone()).to_formatted_string(&fmt)
        );
        assert_eq!(
            "foo=123, bar=456, baz=789",
            Value::Map(map.clone()).to_string()
        );
        assert_eq!(json!(Value::Map(map.clone())), json!(map.clone()));
    }

    #[test]
    fn test_from_option() {
        let value: Option<Value> = None;
        assert_eq!(Value::from(value), Value::Null);
    }

    #[test]
    fn test_from_bool() {
        assert_eq!(Value::from(true), Value::Bool(true));
    }

    #[test]
    fn test_from_vec_u8() {
        assert_eq!(Value::from(vec![42]), Value::Bytes(vec![42]));
    }

    #[test]
    fn test_from_i8() {
        assert_eq!(Value::from(i8::MIN), Value::I8(i8::MIN));
    }

    #[test]
    fn test_from_u8() {
        assert_eq!(Value::from(u8::MAX), Value::U8(u8::MAX));
    }

    #[test]
    fn test_from_i16() {
        assert_eq!(Value::from(i16::MIN), Value::I16(i16::MIN));
    }

    #[test]
    fn test_from_u16() {
        assert_eq!(Value::from(u16::MAX), Value::U16(u16::MAX));
    }

    #[test]
    fn test_from_i32() {
        assert_eq!(Value::from(i32::MIN), Value::I32(i32::MIN));
    }

    #[test]
    fn test_from_u32() {
        assert_eq!(Value::from(u32::MAX), Value::U32(u32::MAX));
    }

    #[test]
    fn test_from_i64() {
        assert_eq!(Value::from(i64::MIN), Value::I64(i64::MIN));
    }

    #[test]
    fn test_from_u64() {
        assert_eq!(Value::from(u64::MAX), Value::U64(u64::MAX));
    }

    #[test]
    fn test_from_isize() {
        assert_eq!(Value::from(isize::MIN), Value::I64(isize::MIN as i64));
    }

    #[test]
    fn test_from_usize() {
        assert_eq!(Value::from(usize::MAX), Value::U64(usize::MAX as u64));
    }

    #[test]
    fn test_from_i128() {
        assert_eq!(Value::from(i128::MIN), Value::I128(i128::MIN));
    }

    #[test]
    fn test_from_u128() {
        assert_eq!(Value::from(u128::MAX), Value::U128(u128::MAX));
    }

    #[test]
    fn test_from_f32() {
        assert_eq!(Value::from(42.1f32), Value::F32(42.1f32));
    }

    #[test]
    fn test_from_f64() {
        assert_eq!(Value::from(42.1f64), Value::F64(42.1f64));
    }

    #[test]
    fn test_from_str() {
        assert_eq!(Value::from("foo"), Value::String("foo".to_string()));
    }

    #[test]
    fn test_from_string() {
        assert_eq!(
            Value::from("foo".to_string()),
            Value::String("foo".to_string())
        );
    }

    #[test]
    fn test_from_decimal() {
        let decimal = rust_decimal::Decimal::from_str("42.1").expect("Invalid decimal");
        assert_eq!(Value::from(decimal), Value::Decimal(decimal));
    }

    #[test]
    fn test_from_date() {
        let date = jiff::civil::date(2000, 12, 31);
        assert_eq!(Value::from(date), Value::Date(date));
    }

    #[test]
    fn test_from_time() {
        let time = jiff::civil::time(12, 13, 14, 15);
        assert_eq!(Value::from(time), Value::Time(time));
    }

    #[test]
    fn test_from_date_time() {
        let date_time = jiff::civil::datetime(2000, 12, 31, 12, 13, 14, 15);
        assert_eq!(Value::from(date_time), Value::DateTime(date_time));
    }

    #[test]
    fn test_from_uuid() -> Result<()> {
        let uuid = "acf5b3e3-4099-4f34-81c7-5803cbc87a2d";
        assert_eq!(
            Value::from(Uuid::from_str(uuid)?),
            Value::Uuid(Uuid::from_str(uuid)?)
        );
        Ok(())
    }

    #[cfg(feature = "json")]
    #[test]
    fn test_from_json() {
        let json = json!(
            {
                "null": null,
                "bool": true,
                "i64": -123,
                "u64": 123,
                "f64": 1.23,
                "string": "foo",
                "array": [true, 42],
                "map": {"key": "value"}
            }
        );
        let value = Value::from(json);
        let expected = Value::Map(
            vec![
                (Value::String("null".to_string()), Value::Null),
                (Value::String("bool".to_string()), Value::Bool(true)),
                (Value::String("i64".to_string()), Value::I64(-123)),
                (Value::String("u64".to_string()), Value::U64(123)),
                (Value::String("f64".to_string()), Value::F64(1.23)),
                (
                    Value::String("string".to_string()),
                    Value::String("foo".to_string()),
                ),
                (
                    Value::String("array".to_string()),
                    Value::Array(vec![Value::Bool(true), Value::U64(42)]),
                ),
                (
                    Value::String("map".to_string()),
                    Value::Map(
                        vec![(
                            Value::String("key".to_string()),
                            Value::String("value".to_string()),
                        )]
                        .into_iter()
                        .collect(),
                    ),
                ),
            ]
            .into_iter()
            .collect(),
        );
        assert_eq!(expected, value);
    }

    #[test]
    fn test_from_vec_value() {
        let array = vec![Value::Bool(true), Value::I8(42)];
        assert_eq!(Value::from(array.clone()), Value::Array(array.clone()));
    }

    #[test]
    fn test_from_index_map() {
        let mut map = IndexMap::new();
        map.insert(Value::String("foo".to_string()), Value::I32(123));
        assert_eq!(Value::from(map.clone()), Value::Map(map.clone()));
    }
}
