//! Runtime values

use alloc::boxed::Box;
use alloc::collections::{BTreeMap, BTreeSet};
use alloc::string::String;
use alloc::vec::Vec;

/// Runtime type representation for CGRF v2
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ValueType {
    Bool,
    U8,
    U16,
    U32,
    U64,
    S8,
    S16,
    S32,
    S64,
    F32,
    F64,
    Char,
    String,
    List(Box<ValueType>),
    Option(Box<ValueType>),
    Result {
        ok: Box<ValueType>,
        err: Box<ValueType>,
    },
    Record(String),  // type name
    Variant(String), // type name
    Tuple(Vec<ValueType>),
    Flags,
}

impl core::fmt::Display for ValueType {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            ValueType::Bool => write!(f, "bool"),
            ValueType::U8 => write!(f, "u8"),
            ValueType::U16 => write!(f, "u16"),
            ValueType::U32 => write!(f, "u32"),
            ValueType::U64 => write!(f, "u64"),
            ValueType::S8 => write!(f, "s8"),
            ValueType::S16 => write!(f, "s16"),
            ValueType::S32 => write!(f, "s32"),
            ValueType::S64 => write!(f, "s64"),
            ValueType::F32 => write!(f, "f32"),
            ValueType::F64 => write!(f, "f64"),
            ValueType::Char => write!(f, "char"),
            ValueType::String => write!(f, "string"),
            ValueType::List(inner) => write!(f, "list<{}>", inner),
            ValueType::Option(inner) => write!(f, "option<{}>", inner),
            ValueType::Result { ok, err } => write!(f, "result<{}, {}>", ok, err),
            ValueType::Record(name) => write!(f, "{}", name),
            ValueType::Variant(name) => write!(f, "{}", name),
            ValueType::Tuple(types) => {
                write!(f, "tuple<")?;
                for (i, t) in types.iter().enumerate() {
                    if i > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}", t)?;
                }
                write!(f, ">")
            }
            ValueType::Flags => write!(f, "flags"),
        }
    }
}

/// A runtime value that can be passed across package boundaries
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Value {
    // Primitives
    Bool(bool),
    U8(u8),
    U16(u16),
    U32(u32),
    U64(u64),
    S8(i8),
    S16(i16),
    S32(i32),
    S64(i64),
    F32(f32),
    F64(f64),
    Char(char),
    String(String),

    // Compound types WITH type info
    List {
        elem_type: ValueType,
        items: Vec<Value>,
    },
    Option {
        inner_type: ValueType,
        value: Option<Box<Value>>,
    },
    Result {
        ok_type: ValueType,
        err_type: ValueType,
        value: core::result::Result<Box<Value>, Box<Value>>,
    },
    Record {
        type_name: String,
        fields: Vec<(String, Value)>,
    },
    Variant {
        type_name: String,
        case_name: String,
        tag: usize,
        payload: Vec<Value>,
    },

    // Keep Tuple as-is (no type info needed - positional)
    Tuple(Vec<Value>),
    Flags(u64),
}

impl Value {
    /// Helper to create a symbol (variant tag 0 with string payload)
    pub fn sym(s: impl Into<String>) -> Self {
        Value::Variant {
            type_name: String::from("expr"),
            case_name: String::from("sym"),
            tag: 0,
            payload: alloc::vec![Value::String(s.into())],
        }
    }

    /// Helper to create a number (variant tag 1 with s64 payload)
    pub fn num(n: i64) -> Self {
        Value::Variant {
            type_name: String::from("expr"),
            case_name: String::from("num"),
            tag: 1,
            payload: alloc::vec![Value::S64(n)],
        }
    }

    /// Helper to create a list (variant tag 4 with list payload)
    pub fn lst(items: Vec<Value>) -> Self {
        Value::Variant {
            type_name: String::from("expr"),
            case_name: String::from("lst"),
            tag: 4,
            payload: alloc::vec![Value::List {
                elem_type: ValueType::Variant(String::from("expr")),
                items,
            }],
        }
    }

    /// Infer the ValueType from this Value
    pub fn infer_type(&self) -> ValueType {
        match self {
            Value::Bool(_) => ValueType::Bool,
            Value::U8(_) => ValueType::U8,
            Value::U16(_) => ValueType::U16,
            Value::U32(_) => ValueType::U32,
            Value::U64(_) => ValueType::U64,
            Value::S8(_) => ValueType::S8,
            Value::S16(_) => ValueType::S16,
            Value::S32(_) => ValueType::S32,
            Value::S64(_) => ValueType::S64,
            Value::F32(_) => ValueType::F32,
            Value::F64(_) => ValueType::F64,
            Value::Char(_) => ValueType::Char,
            Value::String(_) => ValueType::String,
            Value::List { elem_type, .. } => ValueType::List(Box::new(elem_type.clone())),
            Value::Option { inner_type, .. } => ValueType::Option(Box::new(inner_type.clone())),
            Value::Result {
                ok_type, err_type, ..
            } => ValueType::Result {
                ok: Box::new(ok_type.clone()),
                err: Box::new(err_type.clone()),
            },
            Value::Record { type_name, .. } => ValueType::Record(type_name.clone()),
            Value::Variant { type_name, .. } => ValueType::Variant(type_name.clone()),
            Value::Tuple(items) => ValueType::Tuple(items.iter().map(|v| v.infer_type()).collect()),
            Value::Flags(_) => ValueType::Flags,
        }
    }
}

impl core::fmt::Display for Value {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Value::Bool(v) => write!(f, "{}", v),
            Value::U8(v) => write!(f, "{}u8", v),
            Value::U16(v) => write!(f, "{}u16", v),
            Value::U32(v) => write!(f, "{}u32", v),
            Value::U64(v) => write!(f, "{}u64", v),
            Value::S8(v) => write!(f, "{}s8", v),
            Value::S16(v) => write!(f, "{}s16", v),
            Value::S32(v) => write!(f, "{}s32", v),
            Value::S64(v) => write!(f, "{}s64", v),
            Value::F32(v) => {
                // Ensure float always has a decimal point for unambiguous parsing
                let s = alloc::format!("{}", v);
                if v.is_finite() && !s.contains('.') {
                    write!(f, "{}.0f32", s)
                } else {
                    write!(f, "{}f32", s)
                }
            }
            Value::F64(v) => {
                let s = alloc::format!("{}", v);
                if v.is_finite() && !s.contains('.') {
                    write!(f, "{}.0f64", s)
                } else {
                    write!(f, "{}f64", s)
                }
            }
            Value::Char(v) => match v {
                '\n' => write!(f, "'\\n'"),
                '\r' => write!(f, "'\\r'"),
                '\t' => write!(f, "'\\t'"),
                '\\' => write!(f, "'\\\\'"),
                '\'' => write!(f, "'\\''"),
                c => write!(f, "'{}'", c),
            },
            Value::String(v) => {
                write!(f, "\"")?;
                for c in v.chars() {
                    match c {
                        '"' => write!(f, "\\\"")?,
                        '\\' => write!(f, "\\\\")?,
                        '\n' => write!(f, "\\n")?,
                        '\r' => write!(f, "\\r")?,
                        '\t' => write!(f, "\\t")?,
                        c => write!(f, "{}", c)?,
                    }
                }
                write!(f, "\"")
            }
            Value::Tuple(items) => {
                write!(f, "(")?;
                for (i, item) in items.iter().enumerate() {
                    if i > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}", item)?;
                }
                write!(f, ")")
            }
            Value::List { elem_type, items } => {
                if items.is_empty() {
                    // Empty list: annotate elem_type since we can't infer it
                    write!(f, "[]<{}>", elem_type)
                } else {
                    write!(f, "[")?;
                    for (i, item) in items.iter().enumerate() {
                        if i > 0 {
                            write!(f, ", ")?;
                        }
                        write!(f, "{}", item)?;
                    }
                    write!(f, "]")
                }
            }
            Value::Option { inner_type, value } => match value {
                // Always annotate inner_type — the stored type may not match the value's type
                Some(v) => write!(f, "some<{}>({})", inner_type, v),
                None => write!(f, "none<{}>", inner_type),
            },
            Value::Result {
                ok_type,
                err_type,
                value,
            } => match value {
                // Always annotate both types — the stored types may not match the value's type
                Ok(v) => write!(f, "ok<{}, {}>({})", ok_type, err_type, v),
                Err(v) => write!(f, "err<{}, {}>({})", ok_type, err_type, v),
            },
            Value::Record { type_name, fields } => {
                if type_name.is_empty() {
                    write!(f, "{{")?;
                } else {
                    write!(f, "{}{{", type_name)?;
                }
                for (i, (name, value)) in fields.iter().enumerate() {
                    if i > 0 {
                        write!(f, ", ")?;
                    }
                    write!(f, "{}: {}", name, value)?;
                }
                write!(f, "}}")
            }
            Value::Variant {
                type_name,
                case_name,
                payload,
                ..
            } => {
                // Always emit :: to distinguish from keywords (some/none/ok/err)
                write!(f, "{}::{}", type_name, case_name)?;
                if !payload.is_empty() {
                    write!(f, "(")?;
                    for (i, v) in payload.iter().enumerate() {
                        if i > 0 {
                            write!(f, ", ")?;
                        }
                        write!(f, "{}", v)?;
                    }
                    write!(f, ")")?;
                }
                Ok(())
            }
            Value::Flags(v) => write!(f, "flags(0x{:x})", v),
        }
    }
}

// ============================================================================
// From implementations for primitives
// ============================================================================

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

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

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

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

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

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

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

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

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

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

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

impl From<char> for Value {
    fn from(v: char) -> Self {
        Value::Char(v)
    }
}

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

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

// ============================================================================
// KnownValueType — compile-time ValueType for a Rust type.
// ============================================================================
//
// The runtime `infer_type` only works on a concrete value; an empty
// `Vec<T>` or `None: Option<T>` carries no information. To encode an
// empty `Vec<Binding>` correctly (as `list<binding>`, not the default
// `list<s32>`), we need T's ValueType at the type level. Types implement
// `KnownValueType` to declare it — primitives statically, records via
// the `#[derive(GraphValue)]` macro.

/// Compile-time `ValueType` for a Rust type. Used by `From<Vec<T>>` and
/// `From<Option<T>>` so that empty containers still encode with the
/// correct element/inner type.
pub trait KnownValueType {
    fn known_value_type() -> ValueType;
}

macro_rules! known_primitive {
    ($t:ty, $vt:expr) => {
        impl KnownValueType for $t {
            fn known_value_type() -> ValueType {
                $vt
            }
        }
    };
}
known_primitive!(bool, ValueType::Bool);
known_primitive!(u8, ValueType::U8);
known_primitive!(u16, ValueType::U16);
known_primitive!(u32, ValueType::U32);
known_primitive!(u64, ValueType::U64);
known_primitive!(i8, ValueType::S8);
known_primitive!(i16, ValueType::S16);
known_primitive!(i32, ValueType::S32);
known_primitive!(i64, ValueType::S64);
known_primitive!(f32, ValueType::F32);
known_primitive!(f64, ValueType::F64);
known_primitive!(char, ValueType::Char);
known_primitive!(String, ValueType::String);

impl<T: KnownValueType> KnownValueType for Vec<T> {
    fn known_value_type() -> ValueType {
        ValueType::List(Box::new(T::known_value_type()))
    }
}

impl<T: KnownValueType> KnownValueType for Option<T> {
    fn known_value_type() -> ValueType {
        ValueType::Option(Box::new(T::known_value_type()))
    }
}

impl<T: KnownValueType, E: KnownValueType> KnownValueType for core::result::Result<T, E> {
    fn known_value_type() -> ValueType {
        ValueType::Result {
            ok: Box::new(T::known_value_type()),
            err: Box::new(E::known_value_type()),
        }
    }
}

impl<T: KnownValueType> KnownValueType for Box<T> {
    fn known_value_type() -> ValueType {
        T::known_value_type()
    }
}

impl KnownValueType for () {
    fn known_value_type() -> ValueType {
        ValueType::Tuple(Vec::new())
    }
}

/// `Value` is dynamic — its actual ValueType is only known at runtime
/// (`Value::infer_type`). The compile-time fallback is `String`, matching
/// the previous `PackType for Value` behavior. Prefer concrete types when
/// you need accurate static typing.
impl KnownValueType for Value {
    fn known_value_type() -> ValueType {
        ValueType::String
    }
}

impl<A: KnownValueType> KnownValueType for (A,) {
    fn known_value_type() -> ValueType {
        ValueType::Tuple(alloc::vec![A::known_value_type()])
    }
}

impl<A: KnownValueType, B: KnownValueType> KnownValueType for (A, B) {
    fn known_value_type() -> ValueType {
        ValueType::Tuple(alloc::vec![A::known_value_type(), B::known_value_type()])
    }
}

impl<A: KnownValueType, B: KnownValueType, C: KnownValueType> KnownValueType for (A, B, C) {
    fn known_value_type() -> ValueType {
        ValueType::Tuple(alloc::vec![
            A::known_value_type(),
            B::known_value_type(),
            C::known_value_type()
        ])
    }
}

impl<A: KnownValueType, B: KnownValueType, C: KnownValueType, D: KnownValueType> KnownValueType
    for (A, B, C, D)
{
    fn known_value_type() -> ValueType {
        ValueType::Tuple(alloc::vec![
            A::known_value_type(),
            B::known_value_type(),
            C::known_value_type(),
            D::known_value_type()
        ])
    }
}

// ============================================================================
// From implementations for collections — use KnownValueType for the
// element/inner type so empty values still carry correct type info.
// ============================================================================

impl<T: Into<Value> + KnownValueType> From<Vec<T>> for Value {
    fn from(v: Vec<T>) -> Self {
        let items: Vec<Value> = v.into_iter().map(Into::into).collect();
        Value::List {
            elem_type: T::known_value_type(),
            items,
        }
    }
}

impl<T: Into<Value> + KnownValueType, const N: usize> From<[T; N]> for Value {
    fn from(v: [T; N]) -> Self {
        let items: Vec<Value> = v.into_iter().map(Into::into).collect();
        Value::List {
            elem_type: T::known_value_type(),
            items,
        }
    }
}

impl<T: TryFrom<Value, Error = ConversionError>, const N: usize> TryFrom<Value> for [T; N] {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::List { items, .. } => {
                if items.len() != N {
                    return Err(ConversionError::WrongFieldCount {
                        expected: N,
                        got: items.len(),
                    });
                }
                let vec: Vec<T> = items
                    .into_iter()
                    .enumerate()
                    .map(|(i, item)| {
                        T::try_from(item).map_err(|e| ConversionError::IndexError(i, Box::new(e)))
                    })
                    .collect::<Result<Vec<T>, _>>()?;
                vec.try_into().map_err(|_| {
                    ConversionError::ExpectedList(String::from("array conversion failed"))
                })
            }
            other => Err(ConversionError::ExpectedList(format!("{:?}", other))),
        }
    }
}

impl<T: Into<Value> + KnownValueType> From<Option<T>> for Value {
    fn from(v: Option<T>) -> Self {
        Value::Option {
            inner_type: T::known_value_type(),
            value: v.map(|x| Box::new(x.into())),
        }
    }
}

impl<T: Into<Value>> From<Box<T>> for Value {
    fn from(v: Box<T>) -> Self {
        (*v).into()
    }
}

// ============================================================================
// TryFrom implementations for primitives
// ============================================================================

use crate::ConversionError;

impl TryFrom<Value> for bool {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::Bool(x) => Ok(x),
            other => Err(ConversionError::TypeMismatch {
                expected: String::from("bool"),
                got: format!("{:?}", other),
            }),
        }
    }
}

impl TryFrom<Value> for u8 {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::U8(x) => Ok(x),
            other => Err(ConversionError::TypeMismatch {
                expected: String::from("u8"),
                got: format!("{:?}", other),
            }),
        }
    }
}

impl TryFrom<Value> for u16 {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::U16(x) => Ok(x),
            other => Err(ConversionError::TypeMismatch {
                expected: String::from("u16"),
                got: format!("{:?}", other),
            }),
        }
    }
}

impl TryFrom<Value> for u32 {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::U32(x) => Ok(x),
            other => Err(ConversionError::TypeMismatch {
                expected: String::from("u32"),
                got: format!("{:?}", other),
            }),
        }
    }
}

impl TryFrom<Value> for u64 {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::U64(x) => Ok(x),
            other => Err(ConversionError::TypeMismatch {
                expected: String::from("u64"),
                got: format!("{:?}", other),
            }),
        }
    }
}

impl TryFrom<Value> for i8 {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::S8(x) => Ok(x),
            other => Err(ConversionError::TypeMismatch {
                expected: String::from("i8"),
                got: format!("{:?}", other),
            }),
        }
    }
}

impl TryFrom<Value> for i16 {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::S16(x) => Ok(x),
            other => Err(ConversionError::TypeMismatch {
                expected: String::from("i16"),
                got: format!("{:?}", other),
            }),
        }
    }
}

impl TryFrom<Value> for i32 {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::S32(x) => Ok(x),
            other => Err(ConversionError::TypeMismatch {
                expected: String::from("i32"),
                got: format!("{:?}", other),
            }),
        }
    }
}

impl TryFrom<Value> for i64 {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::S64(x) => Ok(x),
            other => Err(ConversionError::TypeMismatch {
                expected: String::from("i64"),
                got: format!("{:?}", other),
            }),
        }
    }
}

impl TryFrom<Value> for f32 {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::F32(x) => Ok(x),
            other => Err(ConversionError::TypeMismatch {
                expected: String::from("f32"),
                got: format!("{:?}", other),
            }),
        }
    }
}

impl TryFrom<Value> for f64 {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::F64(x) => Ok(x),
            other => Err(ConversionError::TypeMismatch {
                expected: String::from("f64"),
                got: format!("{:?}", other),
            }),
        }
    }
}

impl TryFrom<Value> for char {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::Char(x) => Ok(x),
            other => Err(ConversionError::TypeMismatch {
                expected: String::from("char"),
                got: format!("{:?}", other),
            }),
        }
    }
}

impl TryFrom<Value> for String {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::String(x) => Ok(x),
            other => Err(ConversionError::TypeMismatch {
                expected: String::from("String"),
                got: format!("{:?}", other),
            }),
        }
    }
}

impl<T: TryFrom<Value, Error = ConversionError>> TryFrom<Value> for Vec<T> {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::List { items, .. } => items
                .into_iter()
                .enumerate()
                .map(|(i, item)| {
                    T::try_from(item).map_err(|e| ConversionError::IndexError(i, Box::new(e)))
                })
                .collect(),
            other => Err(ConversionError::ExpectedList(format!("{:?}", other))),
        }
    }
}

impl<T: Into<Value> + KnownValueType + Ord> From<BTreeSet<T>> for Value {
    fn from(v: BTreeSet<T>) -> Self {
        let items: Vec<Value> = v.into_iter().map(Into::into).collect();
        Value::List {
            elem_type: T::known_value_type(),
            items,
        }
    }
}

impl<T: TryFrom<Value, Error = ConversionError> + Ord> TryFrom<Value> for BTreeSet<T> {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::List { items, .. } => items
                .into_iter()
                .enumerate()
                .map(|(i, item)| {
                    T::try_from(item).map_err(|e| ConversionError::IndexError(i, Box::new(e)))
                })
                .collect(),
            other => Err(ConversionError::ExpectedList(format!("{:?}", other))),
        }
    }
}

impl<K: Into<Value> + KnownValueType + Ord, V: Into<Value> + KnownValueType> From<BTreeMap<K, V>>
    for Value
{
    fn from(v: BTreeMap<K, V>) -> Self {
        let items: Vec<Value> = v
            .into_iter()
            .map(|(k, v)| Value::Tuple(Vec::from([k.into(), v.into()])))
            .collect();
        Value::List {
            elem_type: ValueType::Tuple(alloc::vec![K::known_value_type(), V::known_value_type()]),
            items,
        }
    }
}

impl<
        K: TryFrom<Value, Error = ConversionError> + Ord,
        V: TryFrom<Value, Error = ConversionError>,
    > TryFrom<Value> for BTreeMap<K, V>
{
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::List { items, .. } => items
                .into_iter()
                .enumerate()
                .map(|(i, item)| match item {
                    Value::Tuple(mut fields) if fields.len() == 2 => {
                        let v_val = fields.pop().unwrap();
                        let k_val = fields.pop().unwrap();
                        let k = K::try_from(k_val)
                            .map_err(|e| ConversionError::IndexError(i, Box::new(e)))?;
                        let v = V::try_from(v_val)
                            .map_err(|e| ConversionError::IndexError(i, Box::new(e)))?;
                        Ok((k, v))
                    }
                    other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
                })
                .collect(),
            other => Err(ConversionError::ExpectedList(format!("{:?}", other))),
        }
    }
}

// ============================================================================
// FromValue trait - avoids coherence issues with TryFrom for Option<T>
// ============================================================================

/// Trait for converting from a Value.
///
/// This trait exists to avoid coherence issues with Rust's blanket
/// `impl<T, U> TryFrom<U> for T where U: Into<T>` when implementing
/// conversions for generic types like `Option<T>`.
pub trait FromValue: Sized {
    fn from_value(v: Value) -> Result<Self, ConversionError>;
}

/// Blanket implementation for all types that implement TryFrom<Value>
impl<T: TryFrom<Value, Error = ConversionError>> FromValue for T {
    fn from_value(v: Value) -> Result<Self, ConversionError> {
        T::try_from(v)
    }
}

/// FromValue implementation for Value itself (identity conversion)
impl FromValue for Value {
    fn from_value(v: Value) -> Result<Self, ConversionError> {
        Ok(v)
    }
}

/// FromValue implementation for Option<T> - uses FromValue bound to avoid coherence issues
impl<T: FromValue> FromValue for Option<T> {
    fn from_value(v: Value) -> Result<Self, ConversionError> {
        match v {
            Value::Option { value: None, .. } => Ok(None),
            Value::Option {
                value: Some(inner), ..
            } => {
                let value = T::from_value(*inner)?;
                Ok(Some(value))
            }
            other => Err(ConversionError::ExpectedOption(format!("{:?}", other))),
        }
    }
}

/// FromValue implementation for Result<T, E> - uses FromValue bounds to support nested Option types
impl<T: FromValue, E: FromValue> FromValue for core::result::Result<T, E> {
    fn from_value(v: Value) -> Result<Self, ConversionError> {
        match v {
            Value::Result {
                value: Ok(inner), ..
            } => {
                let value = T::from_value(*inner)
                    .map_err(|e| ConversionError::PayloadError(Box::new(e)))?;
                Ok(Ok(value))
            }
            Value::Result {
                value: Err(inner), ..
            } => {
                let value = E::from_value(*inner)
                    .map_err(|e| ConversionError::PayloadError(Box::new(e)))?;
                Ok(Err(value))
            }
            // Also support legacy variant encoding for backwards compatibility
            Value::Variant {
                tag: 0, payload, ..
            } if !payload.is_empty() => {
                let value = T::from_value(payload.into_iter().next().unwrap())
                    .map_err(|e| ConversionError::PayloadError(Box::new(e)))?;
                Ok(Ok(value))
            }
            Value::Variant {
                tag: 1, payload, ..
            } if !payload.is_empty() => {
                let value = E::from_value(payload.into_iter().next().unwrap())
                    .map_err(|e| ConversionError::PayloadError(Box::new(e)))?;
                Ok(Err(value))
            }
            Value::Variant { tag, .. } => Err(ConversionError::UnknownTag { tag, max: 1 }),
            other => Err(ConversionError::ExpectedVariant(format!("{:?}", other))),
        }
    }
}

// ============================================================================
// Tuple conversions (for common sizes)
// ============================================================================

// Empty tuple / unit
impl From<()> for Value {
    fn from(_: ()) -> Self {
        Value::Tuple(Vec::new())
    }
}

impl TryFrom<Value> for () {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::Tuple(items) if items.is_empty() => Ok(()),
            other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
        }
    }
}

// 1-tuple
impl<A: Into<Value>> From<(A,)> for Value {
    fn from((a,): (A,)) -> Self {
        Value::Tuple(alloc::vec![a.into()])
    }
}

impl<A: TryFrom<Value, Error = ConversionError>> TryFrom<Value> for (A,) {
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::Tuple(mut items) if items.len() == 1 => {
                let a = A::try_from(items.remove(0))
                    .map_err(|e| ConversionError::IndexError(0, Box::new(e)))?;
                Ok((a,))
            }
            other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
        }
    }
}

// 2-tuple
impl<A: Into<Value>, B: Into<Value>> From<(A, B)> for Value {
    fn from((a, b): (A, B)) -> Self {
        Value::Tuple(alloc::vec![a.into(), b.into()])
    }
}

impl<A: TryFrom<Value, Error = ConversionError>, B: TryFrom<Value, Error = ConversionError>>
    TryFrom<Value> for (A, B)
{
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::Tuple(mut items) if items.len() == 2 => {
                let b = B::try_from(items.remove(1))
                    .map_err(|e| ConversionError::IndexError(1, Box::new(e)))?;
                let a = A::try_from(items.remove(0))
                    .map_err(|e| ConversionError::IndexError(0, Box::new(e)))?;
                Ok((a, b))
            }
            other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
        }
    }
}

// 3-tuple
impl<A: Into<Value>, B: Into<Value>, C: Into<Value>> From<(A, B, C)> for Value {
    fn from((a, b, c): (A, B, C)) -> Self {
        Value::Tuple(alloc::vec![a.into(), b.into(), c.into()])
    }
}

impl<
        A: TryFrom<Value, Error = ConversionError>,
        B: TryFrom<Value, Error = ConversionError>,
        C: TryFrom<Value, Error = ConversionError>,
    > TryFrom<Value> for (A, B, C)
{
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::Tuple(mut items) if items.len() == 3 => {
                let c = C::try_from(items.remove(2))
                    .map_err(|e| ConversionError::IndexError(2, Box::new(e)))?;
                let b = B::try_from(items.remove(1))
                    .map_err(|e| ConversionError::IndexError(1, Box::new(e)))?;
                let a = A::try_from(items.remove(0))
                    .map_err(|e| ConversionError::IndexError(0, Box::new(e)))?;
                Ok((a, b, c))
            }
            other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
        }
    }
}

// 4-tuple
impl<A: Into<Value>, B: Into<Value>, C: Into<Value>, D: Into<Value>> From<(A, B, C, D)> for Value {
    fn from((a, b, c, d): (A, B, C, D)) -> Self {
        Value::Tuple(alloc::vec![a.into(), b.into(), c.into(), d.into()])
    }
}

impl<
        A: TryFrom<Value, Error = ConversionError>,
        B: TryFrom<Value, Error = ConversionError>,
        C: TryFrom<Value, Error = ConversionError>,
        D: TryFrom<Value, Error = ConversionError>,
    > TryFrom<Value> for (A, B, C, D)
{
    type Error = ConversionError;
    fn try_from(v: Value) -> Result<Self, Self::Error> {
        match v {
            Value::Tuple(mut items) if items.len() == 4 => {
                let d = D::try_from(items.remove(3))
                    .map_err(|e| ConversionError::IndexError(3, Box::new(e)))?;
                let c = C::try_from(items.remove(2))
                    .map_err(|e| ConversionError::IndexError(2, Box::new(e)))?;
                let b = B::try_from(items.remove(1))
                    .map_err(|e| ConversionError::IndexError(1, Box::new(e)))?;
                let a = A::try_from(items.remove(0))
                    .map_err(|e| ConversionError::IndexError(0, Box::new(e)))?;
                Ok((a, b, c, d))
            }
            other => Err(ConversionError::ExpectedTuple(format!("{:?}", other))),
        }
    }
}

// ============================================================================
// Result conversions (now using Value::Result directly)
// ============================================================================

impl<T: Into<Value> + KnownValueType, E: Into<Value> + KnownValueType>
    From<core::result::Result<T, E>> for Value
{
    fn from(r: core::result::Result<T, E>) -> Self {
        let ok_type = T::known_value_type();
        let err_type = E::known_value_type();
        let value = match r {
            Ok(v) => Ok(Box::new(v.into())),
            Err(e) => Err(Box::new(e.into())),
        };
        Value::Result {
            ok_type,
            err_type,
            value,
        }
    }
}

// Note: TryFrom<Value> for Result<T, E> is NOT implemented directly.
// Use FromValue::from_value() instead, which supports nested Option types.
// The FromValue impl for Result<T, E> is above with the other FromValue impls.

use alloc::format;
