use rayon::prelude::*;
use simd_json::OwnedValue as Value;
use simd_json::StaticNode;
use simd_json::prelude::*;

use super::ast::{BoolOp, CompareOp, Filter, FunctionCall, ObjectKey};
use super::builtins;
use crate::error::EvalError;

/// Threshold for parallel array operations
const PARALLEL_THRESHOLD: usize = 10_000;

pub fn eval(filter: &Filter, value: &Value) -> Result<Vec<Value>, EvalError> {
    match filter {
        Filter::Identity => Ok(vec![value.clone()]),
        Filter::Field(name) => match value {
            Value::Object(map) => Ok(vec![
                map.get(name)
                    .cloned()
                    .unwrap_or(Value::Static(StaticNode::Null)),
            ]),
            _ => Ok(vec![Value::Static(StaticNode::Null)]),
        },
        Filter::Index(n) => match value {
            Value::Array(arr) => {
                let idx = if *n >= 0 {
                    *n as usize
                } else {
                    arr.len().checked_sub((-*n) as usize).unwrap_or(usize::MAX)
                };
                Ok(vec![
                    arr.get(idx)
                        .cloned()
                        .unwrap_or(Value::Static(StaticNode::Null)),
                ])
            }
            _ => Ok(vec![Value::Static(StaticNode::Null)]),
        },
        Filter::Slice(start, end) => match value {
            Value::Array(arr) => {
                let len = arr.len() as i64;

                // Resolve start index (default 0)
                let start_idx = match start {
                    Some(s) if *s >= 0 => (*s as usize).min(arr.len()),
                    Some(s) => (len + *s).max(0) as usize,
                    None => 0,
                };

                // Resolve end index (default len)
                let end_idx = match end {
                    Some(e) if *e >= 0 => (*e as usize).min(arr.len()),
                    Some(e) => (len + *e).max(0) as usize,
                    None => arr.len(),
                };

                // Handle case where start > end
                if start_idx >= end_idx {
                    Ok(vec![Value::Array(Box::default())])
                } else {
                    Ok(vec![Value::Array(Box::new(
                        arr[start_idx..end_idx].to_vec(),
                    ))])
                }
            }
            Value::String(s) => {
                let chars: Vec<char> = s.chars().collect();
                let len = chars.len() as i64;

                let start_idx = match start {
                    Some(st) if *st >= 0 => (*st as usize).min(chars.len()),
                    Some(st) => (len + *st).max(0) as usize,
                    None => 0,
                };

                let end_idx = match end {
                    Some(e) if *e >= 0 => (*e as usize).min(chars.len()),
                    Some(e) => (len + *e).max(0) as usize,
                    None => chars.len(),
                };

                if start_idx >= end_idx {
                    Ok(vec![Value::String(String::new())])
                } else {
                    Ok(vec![Value::String(
                        chars[start_idx..end_idx].iter().collect(),
                    )])
                }
            }
            _ => Ok(vec![Value::Static(StaticNode::Null)]),
        },
        Filter::Iterate => match value {
            Value::Array(arr) if arr.len() >= PARALLEL_THRESHOLD => {
                Ok(arr.par_iter().cloned().collect())
            }
            Value::Array(arr) => Ok(arr.to_vec()),
            Value::Object(map) => Ok(map.values().cloned().collect()),
            _ => Err(EvalError::CannotIterate {
                value: value.clone(),
                position: 0, // Position will be determined by caller
            }),
        },
        Filter::Optional(inner) => {
            // Try to evaluate, suppress errors by returning empty
            match eval(inner, value) {
                Ok(results) => Ok(results),
                Err(_) => Ok(vec![]),
            }
        }
        Filter::Pipe(left, right) => {
            let left_results = eval(left, value)?;
            let mut results = Vec::new();
            for v in left_results {
                results.extend(eval(right, &v)?);
            }
            Ok(results)
        }
        Filter::Builtin(b) => builtins::eval(b, value),
        Filter::Function(func) => eval_function(func, value),
        Filter::Literal(lit) => Ok(vec![lit.clone()]),
        Filter::Compare(left, op, right) => eval_compare(left, *op, right, value),
        Filter::BoolOp(left, op, right) => eval_bool_op(left, *op, right, value),
        Filter::Array(element_filters) => {
            let mut array_elements = Vec::new();
            for elem_filter in element_filters {
                let results = eval(elem_filter, value)?;
                // Collect all results (handles .[] producing multiple values)
                array_elements.extend(results);
            }
            Ok(vec![Value::Array(Box::new(array_elements))])
        }
        Filter::Object(pairs) => {
            let mut obj = simd_json::owned::Object::new();
            for (key, value_filter) in pairs {
                // Resolve key (static or dynamic)
                let key_str = match key {
                    ObjectKey::Static(s) => s.clone(),
                    ObjectKey::Dynamic(key_filter) => {
                        let key_results = eval(key_filter, value)?;
                        match key_results.into_iter().next() {
                            Some(Value::String(s)) => s,
                            Some(other) => {
                                return Err(EvalError::TypeError {
                                    message: format!(
                                        "object key must be string, got {}",
                                        type_name(&other)
                                    ),
                                    position: 0,
                                });
                            }
                            None => {
                                return Err(EvalError::TypeError {
                                    message: "object key expression produced no value".to_string(),
                                    position: 0,
                                });
                            }
                        }
                    }
                };

                let results = eval(value_filter, value)?;
                // Take first result for object values
                let val = results
                    .into_iter()
                    .next()
                    .unwrap_or(Value::Static(StaticNode::Null));
                obj.insert(key_str, val);
            }
            Ok(vec![Value::Object(Box::new(obj))])
        }
        Filter::IfThenElse {
            condition,
            then_branch,
            else_branch,
        } => {
            let cond_results = eval(condition, value)?;
            let is_truthy = cond_results.iter().any(|v| {
                !matches!(
                    v,
                    Value::Static(StaticNode::Null) | Value::Static(StaticNode::Bool(false))
                )
            });

            if is_truthy {
                eval(then_branch, value)
            } else {
                eval(else_branch, value)
            }
        }
        Filter::Alternative(left, right) => {
            let left_results = eval(left, value)?;

            // Check if left produced any non-false, non-null value
            let has_value = left_results.iter().any(|v| {
                !matches!(
                    v,
                    Value::Static(StaticNode::Null) | Value::Static(StaticNode::Bool(false))
                )
            });

            if has_value {
                // Filter out false/null from results
                let filtered: Vec<Value> = left_results
                    .into_iter()
                    .filter(|v| {
                        !matches!(
                            v,
                            Value::Static(StaticNode::Null)
                                | Value::Static(StaticNode::Bool(false))
                        )
                    })
                    .collect();
                if filtered.is_empty() {
                    eval(right, value)
                } else {
                    Ok(filtered)
                }
            } else {
                eval(right, value)
            }
        }
    }
}

fn type_name(v: &Value) -> &'static str {
    match v {
        Value::Static(StaticNode::Null) => "null",
        Value::Static(StaticNode::Bool(_)) => "boolean",
        Value::Static(StaticNode::I64(_) | StaticNode::U64(_) | StaticNode::F64(_)) => "number",
        Value::String(_) => "string",
        Value::Array(_) => "array",
        Value::Object(_) => "object",
    }
}

fn eval_function(func: &FunctionCall, value: &Value) -> Result<Vec<Value>, EvalError> {
    match func {
        FunctionCall::Map(inner) => eval_map(inner, value),
        FunctionCall::Select(inner) => eval_select(inner, value),
        FunctionCall::SortBy(inner) => eval_sort_by(inner, value),
        FunctionCall::GroupBy(inner) => eval_group_by(inner, value),
        FunctionCall::UniqueBy(inner) => eval_unique_by(inner, value),
        FunctionCall::MinBy(inner) => eval_min_by(inner, value),
        FunctionCall::MaxBy(inner) => eval_max_by(inner, value),
        FunctionCall::Has(key) => eval_has(key, value),
        FunctionCall::Split(delim) => eval_split(delim, value),
        FunctionCall::Join(sep) => eval_join(sep, value),
        FunctionCall::StartsWith(prefix) => eval_startswith(prefix, value),
        FunctionCall::EndsWith(suffix) => eval_endswith(suffix, value),
        FunctionCall::Contains(inner) => eval_contains(inner, value),
        FunctionCall::WithEntries(inner) => eval_with_entries(inner, value),
    }
}

fn eval_has(key: &str, value: &Value) -> Result<Vec<Value>, EvalError> {
    match value {
        Value::Object(map) => Ok(vec![Value::Static(StaticNode::Bool(map.contains_key(key)))]),
        Value::Array(arr) => {
            // has(n) for arrays checks if index exists
            if let Ok(idx) = key.parse::<usize>() {
                Ok(vec![Value::Static(StaticNode::Bool(idx < arr.len()))])
            } else {
                Ok(vec![Value::Static(StaticNode::Bool(false))])
            }
        }
        _ => Ok(vec![Value::Static(StaticNode::Bool(false))]),
    }
}

fn eval_split(delim: &str, value: &Value) -> Result<Vec<Value>, EvalError> {
    match value {
        Value::String(s) => {
            // jq special cases
            if s.is_empty() {
                // Empty string split returns empty array
                return Ok(vec![Value::Array(Box::default())]);
            }
            if delim.is_empty() {
                // Empty delimiter splits into characters
                let parts: Vec<Value> = s.chars().map(|c| Value::String(c.to_string())).collect();
                return Ok(vec![Value::Array(Box::new(parts))]);
            }
            let parts: Vec<Value> = s
                .split(delim)
                .map(|p| Value::String(p.to_string()))
                .collect();
            Ok(vec![Value::Array(Box::new(parts))])
        }
        _ => Err(EvalError::TypeError {
            message: format!("split requires string, got {}", type_name(value)),
            position: 0,
        }),
    }
}

fn eval_join(sep: &str, value: &Value) -> Result<Vec<Value>, EvalError> {
    match value {
        Value::Array(arr) => {
            let mut strings = Vec::new();
            for v in arr.iter() {
                match v {
                    Value::String(s) => strings.push(s.clone()),
                    Value::Static(StaticNode::Null) => strings.push(String::new()), // jq treats null as empty string
                    _ => {
                        return Err(EvalError::TypeError {
                            message: format!(
                                "join requires array of strings, got {} in array",
                                type_name(v)
                            ),
                            position: 0,
                        });
                    }
                }
            }
            Ok(vec![Value::String(strings.join(sep))])
        }
        _ => Err(EvalError::TypeError {
            message: format!("join requires array, got {}", type_name(value)),
            position: 0,
        }),
    }
}

fn eval_startswith(prefix: &str, value: &Value) -> Result<Vec<Value>, EvalError> {
    match value {
        Value::String(s) => Ok(vec![Value::Static(StaticNode::Bool(s.starts_with(prefix)))]),
        _ => Err(EvalError::TypeError {
            message: format!("startswith requires string, got {}", type_name(value)),
            position: 0,
        }),
    }
}

fn eval_endswith(suffix: &str, value: &Value) -> Result<Vec<Value>, EvalError> {
    match value {
        Value::String(s) => Ok(vec![Value::Static(StaticNode::Bool(s.ends_with(suffix)))]),
        _ => Err(EvalError::TypeError {
            message: format!("endswith requires string, got {}", type_name(value)),
            position: 0,
        }),
    }
}

fn eval_contains(inner: &Filter, value: &Value) -> Result<Vec<Value>, EvalError> {
    let needle_results = eval(inner, value)?;
    let needle = needle_results
        .into_iter()
        .next()
        .unwrap_or(Value::Static(StaticNode::Null));

    Ok(vec![Value::Static(StaticNode::Bool(value_contains(
        value, &needle,
    )))])
}

/// Recursive contains check following jq semantics:
/// - strings: b is substring of a
/// - arrays: all elements of b are contained in some element of a
/// - objects: all key-value pairs of b have matching keys in a with contained values
/// - scalars: equality
fn value_contains(a: &Value, b: &Value) -> bool {
    match (a, b) {
        (Value::String(haystack), Value::String(needle)) => haystack.contains(needle.as_str()),
        (Value::Array(arr), Value::Array(needle_arr)) => {
            // All elements of needle must be contained in some element of arr
            needle_arr
                .iter()
                .all(|needle_elem| arr.iter().any(|elem| value_contains(elem, needle_elem)))
        }
        (Value::Object(obj), Value::Object(needle_obj)) => needle_obj
            .iter()
            .all(|(k, v)| obj.get(k).map(|ov| value_contains(ov, v)).unwrap_or(false)),
        _ => compare_values(a, b) == Some(std::cmp::Ordering::Equal),
    }
}

/// with_entries(f) is equivalent to: to_entries | map(f) | from_entries
fn eval_with_entries(inner: &Filter, value: &Value) -> Result<Vec<Value>, EvalError> {
    match value {
        Value::Object(obj) => {
            // Convert to entries
            let entries: Vec<Value> = obj
                .iter()
                .map(|(k, v)| {
                    let mut entry = simd_json::owned::Object::new();
                    entry.insert("key".to_string(), Value::String(k.clone()));
                    entry.insert("value".to_string(), v.clone());
                    Value::Object(Box::new(entry))
                })
                .collect();

            // Apply filter to each entry
            let mut transformed = Vec::new();
            for entry in entries {
                transformed.extend(eval(inner, &entry)?);
            }

            // Convert back to object
            let mut result = simd_json::owned::Object::new();
            for entry in transformed {
                // Extract key: try "key", "k", "name"
                let key = entry
                    .get("key")
                    .or_else(|| entry.get("k"))
                    .or_else(|| entry.get("name"))
                    .and_then(|k| k.as_str())
                    .ok_or_else(|| EvalError::TypeError {
                        message: "Cannot use null as object key".to_string(),
                        position: 0,
                    })?;

                // Extract value: try "value", "v" (default to null)
                let val = entry
                    .get("value")
                    .or_else(|| entry.get("v"))
                    .cloned()
                    .unwrap_or(Value::Static(StaticNode::Null));

                result.insert(key.to_string(), val);
            }

            Ok(vec![Value::Object(Box::new(result))])
        }
        _ => Err(EvalError::TypeError {
            message: format!("with_entries requires object, got {}", type_name(value)),
            position: 0,
        }),
    }
}

fn eval_map(inner: &Filter, value: &Value) -> Result<Vec<Value>, EvalError> {
    match value {
        Value::Array(arr) => {
            let mut results = Vec::new();
            for elem in arr.iter() {
                results.extend(eval(inner, elem)?);
            }
            Ok(vec![Value::Array(Box::new(results))])
        }
        _ => Err(EvalError::TypeError {
            message: format!("map requires array, got {}", type_name(value)),
            position: 0,
        }),
    }
}

fn eval_select(inner: &Filter, value: &Value) -> Result<Vec<Value>, EvalError> {
    let results = eval(inner, value)?;
    // In jq, select keeps values where the condition is truthy
    // Falsy values are: false and null
    // Everything else (including 0, "", [], {}) is truthy
    let is_truthy = results.iter().any(|v| {
        !matches!(
            v,
            Value::Static(StaticNode::Null) | Value::Static(StaticNode::Bool(false))
        )
    });

    if is_truthy {
        Ok(vec![value.clone()])
    } else {
        Ok(vec![]) // No output
    }
}

fn eval_sort_by(inner: &Filter, value: &Value) -> Result<Vec<Value>, EvalError> {
    match value {
        Value::Array(arr) => {
            // Extract keys and pair with elements
            let mut keyed: Vec<(Value, Value)> = arr
                .iter()
                .map(|elem| {
                    let key = eval(inner, elem)?
                        .into_iter()
                        .next()
                        .unwrap_or(Value::Static(StaticNode::Null));
                    Ok((key, elem.clone()))
                })
                .collect::<Result<Vec<_>, EvalError>>()?;

            // Sort by key using existing compare_values (stable sort)
            keyed.sort_by(|(a, _), (b, _)| {
                compare_values(a, b).unwrap_or(std::cmp::Ordering::Equal)
            });

            let sorted: Vec<Value> = keyed.into_iter().map(|(_, v)| v).collect();
            Ok(vec![Value::Array(Box::new(sorted))])
        }
        _ => Err(EvalError::TypeError {
            message: format!("sort_by requires array, got {}", type_name(value)),
            position: 0,
        }),
    }
}

fn eval_group_by(inner: &Filter, value: &Value) -> Result<Vec<Value>, EvalError> {
    match value {
        Value::Array(arr) => {
            // Extract keys and group elements
            let mut groups: Vec<(Value, Vec<Value>)> = vec![];

            for elem in arr.iter() {
                let key = eval(inner, elem)?
                    .into_iter()
                    .next()
                    .unwrap_or(Value::Static(StaticNode::Null));

                // Find existing group with same key
                if let Some((_, group)) = groups
                    .iter_mut()
                    .find(|(k, _)| compare_values(k, &key) == Some(std::cmp::Ordering::Equal))
                {
                    group.push(elem.clone());
                } else {
                    groups.push((key, vec![elem.clone()]));
                }
            }

            // Sort groups by key (jq behavior)
            groups.sort_by(|(a, _), (b, _)| {
                compare_values(a, b).unwrap_or(std::cmp::Ordering::Equal)
            });

            // Return array of arrays
            let result: Vec<Value> = groups
                .into_iter()
                .map(|(_, group)| Value::Array(Box::new(group)))
                .collect();
            Ok(vec![Value::Array(Box::new(result))])
        }
        _ => Err(EvalError::TypeError {
            message: format!("group_by requires array, got {}", type_name(value)),
            position: 0,
        }),
    }
}

fn eval_unique_by(inner: &Filter, value: &Value) -> Result<Vec<Value>, EvalError> {
    match value {
        Value::Array(arr) => {
            let mut seen: Vec<Value> = vec![];
            let mut result: Vec<Value> = vec![];

            for elem in arr.iter() {
                let key = eval(inner, elem)?
                    .into_iter()
                    .next()
                    .unwrap_or(Value::Static(StaticNode::Null));

                // Check if we've seen this key
                let is_new = !seen
                    .iter()
                    .any(|k| compare_values(k, &key) == Some(std::cmp::Ordering::Equal));

                if is_new {
                    seen.push(key);
                    result.push(elem.clone());
                }
            }

            Ok(vec![Value::Array(Box::new(result))])
        }
        _ => Err(EvalError::TypeError {
            message: format!("unique_by requires array, got {}", type_name(value)),
            position: 0,
        }),
    }
}

fn eval_min_by(inner: &Filter, value: &Value) -> Result<Vec<Value>, EvalError> {
    eval_extremum_by(inner, value, true)
}

fn eval_max_by(inner: &Filter, value: &Value) -> Result<Vec<Value>, EvalError> {
    eval_extremum_by(inner, value, false)
}

fn eval_extremum_by(inner: &Filter, value: &Value, is_min: bool) -> Result<Vec<Value>, EvalError> {
    let func_name = if is_min { "min_by" } else { "max_by" };

    match value {
        Value::Array(arr) if arr.is_empty() => Ok(vec![Value::Static(StaticNode::Null)]),
        Value::Array(arr) => {
            let mut best_elem = &arr[0];
            let mut best_key = eval(inner, best_elem)?
                .into_iter()
                .next()
                .unwrap_or(Value::Static(StaticNode::Null));

            for elem in arr.iter().skip(1) {
                let key = eval(inner, elem)?
                    .into_iter()
                    .next()
                    .unwrap_or(Value::Static(StaticNode::Null));

                let cmp = compare_values(&key, &best_key);
                let should_replace = if is_min {
                    cmp == Some(std::cmp::Ordering::Less)
                } else {
                    cmp == Some(std::cmp::Ordering::Greater)
                };

                if should_replace {
                    best_elem = elem;
                    best_key = key;
                }
            }

            Ok(vec![best_elem.clone()])
        }
        _ => Err(EvalError::TypeError {
            message: format!("{} requires array, got {}", func_name, type_name(value)),
            position: 0,
        }),
    }
}

fn eval_compare(
    left: &Filter,
    op: CompareOp,
    right: &Filter,
    value: &Value,
) -> Result<Vec<Value>, EvalError> {
    let left_results = eval(left, value)?;
    let right_results = eval(right, value)?;

    // Take first result from each side
    let left_val = left_results
        .into_iter()
        .next()
        .unwrap_or(Value::Static(StaticNode::Null));
    let right_val = right_results
        .into_iter()
        .next()
        .unwrap_or(Value::Static(StaticNode::Null));

    let result = match op {
        CompareOp::Eq => compare_values(&left_val, &right_val) == Some(std::cmp::Ordering::Equal),
        CompareOp::Ne => compare_values(&left_val, &right_val) != Some(std::cmp::Ordering::Equal),
        CompareOp::Lt => compare_values(&left_val, &right_val) == Some(std::cmp::Ordering::Less),
        CompareOp::Le => matches!(
            compare_values(&left_val, &right_val),
            Some(std::cmp::Ordering::Less | std::cmp::Ordering::Equal)
        ),
        CompareOp::Gt => compare_values(&left_val, &right_val) == Some(std::cmp::Ordering::Greater),
        CompareOp::Ge => matches!(
            compare_values(&left_val, &right_val),
            Some(std::cmp::Ordering::Greater | std::cmp::Ordering::Equal)
        ),
    };

    Ok(vec![Value::Static(StaticNode::Bool(result))])
}

fn eval_bool_op(
    left: &Filter,
    op: BoolOp,
    right: &Filter,
    value: &Value,
) -> Result<Vec<Value>, EvalError> {
    // Evaluate left side first
    let left_results = eval(left, value)?;
    let left_truthy = left_results.iter().any(|v| {
        !matches!(
            v,
            Value::Static(StaticNode::Null) | Value::Static(StaticNode::Bool(false))
        )
    });

    // Short-circuit evaluation
    match op {
        BoolOp::And => {
            if !left_truthy {
                // Short-circuit: false and X = false
                Ok(vec![Value::Static(StaticNode::Bool(false))])
            } else {
                // Evaluate right side
                let right_results = eval(right, value)?;
                let right_truthy = right_results.iter().any(|v| {
                    !matches!(
                        v,
                        Value::Static(StaticNode::Null) | Value::Static(StaticNode::Bool(false))
                    )
                });
                Ok(vec![Value::Static(StaticNode::Bool(right_truthy))])
            }
        }
        BoolOp::Or => {
            if left_truthy {
                // Short-circuit: true or X = true
                Ok(vec![Value::Static(StaticNode::Bool(true))])
            } else {
                // Evaluate right side
                let right_results = eval(right, value)?;
                let right_truthy = right_results.iter().any(|v| {
                    !matches!(
                        v,
                        Value::Static(StaticNode::Null) | Value::Static(StaticNode::Bool(false))
                    )
                });
                Ok(vec![Value::Static(StaticNode::Bool(right_truthy))])
            }
        }
    }
}

/// Compare two JSON values following jq semantics.
/// Returns None if values are not comparable (different types for ordering).
fn compare_values(a: &Value, b: &Value) -> Option<std::cmp::Ordering> {
    use std::cmp::Ordering;

    match (a, b) {
        // Null
        (Value::Static(StaticNode::Null), Value::Static(StaticNode::Null)) => Some(Ordering::Equal),

        // Booleans: false < true
        (Value::Static(StaticNode::Bool(a)), Value::Static(StaticNode::Bool(b))) => Some(a.cmp(b)),

        // Numbers
        (Value::Static(StaticNode::I64(a)), Value::Static(StaticNode::I64(b))) => Some(a.cmp(b)),
        (Value::Static(StaticNode::U64(a)), Value::Static(StaticNode::U64(b))) => Some(a.cmp(b)),
        (Value::Static(StaticNode::F64(a)), Value::Static(StaticNode::F64(b))) => a.partial_cmp(b),
        (Value::Static(StaticNode::I64(a)), Value::Static(StaticNode::U64(b))) => {
            Some((*a as i128).cmp(&(*b as i128)))
        }
        (Value::Static(StaticNode::U64(a)), Value::Static(StaticNode::I64(b))) => {
            Some((*a as i128).cmp(&(*b as i128)))
        }
        (Value::Static(StaticNode::I64(a)), Value::Static(StaticNode::F64(b))) => {
            (*a as f64).partial_cmp(b)
        }
        (Value::Static(StaticNode::F64(a)), Value::Static(StaticNode::I64(b))) => {
            a.partial_cmp(&(*b as f64))
        }
        (Value::Static(StaticNode::U64(a)), Value::Static(StaticNode::F64(b))) => {
            (*a as f64).partial_cmp(b)
        }
        (Value::Static(StaticNode::F64(a)), Value::Static(StaticNode::U64(b))) => {
            a.partial_cmp(&(*b as f64))
        }

        // Strings: lexicographic
        (Value::String(a), Value::String(b)) => Some(a.cmp(b)),

        // Arrays: lexicographic comparison
        (Value::Array(a), Value::Array(b)) => {
            for (av, bv) in a.iter().zip(b.iter()) {
                match compare_values(av, bv) {
                    Some(Ordering::Equal) => continue,
                    other => return other,
                }
            }
            Some(a.len().cmp(&b.len()))
        }

        // Objects: compare by sorted keys, then values
        (Value::Object(a), Value::Object(b)) => {
            let mut a_keys: Vec<_> = a.keys().collect();
            let mut b_keys: Vec<_> = b.keys().collect();
            a_keys.sort();
            b_keys.sort();

            // First compare keys
            for (ak, bk) in a_keys.iter().zip(b_keys.iter()) {
                match ak.cmp(bk) {
                    Ordering::Equal => continue,
                    other => return Some(other),
                }
            }
            if a_keys.len() != b_keys.len() {
                return Some(a_keys.len().cmp(&b_keys.len()));
            }

            // Keys are equal, compare values
            for k in a_keys {
                match compare_values(&a[k], &b[k]) {
                    Some(Ordering::Equal) => continue,
                    other => return other,
                }
            }
            Some(Ordering::Equal)
        }

        // Different types: only equality is well-defined (and it's false)
        _ => None,
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use simd_json::json;

    // Identity tests
    #[test]
    fn test_identity() {
        let value = json!({"name": "alice"});
        let result = eval(&Filter::Identity, &value).unwrap();
        assert_eq!(result, vec![value]);
    }

    // Field access tests
    #[test]
    fn test_field_access() {
        let value = json!({"name": "alice", "age": 30});
        let result = eval(&Filter::Field("name".to_string()), &value).unwrap();
        assert_eq!(result, vec![json!("alice")]);
    }

    #[test]
    fn test_field_missing() {
        let value = json!({"name": "alice"});
        let result = eval(&Filter::Field("missing".to_string()), &value).unwrap();
        assert_eq!(result, vec![Value::Static(StaticNode::Null)]);
    }

    #[test]
    fn test_field_on_non_object() {
        let result = eval(&Filter::Field("foo".to_string()), &json!("string")).unwrap();
        assert_eq!(result, vec![Value::Static(StaticNode::Null)]);

        let result = eval(&Filter::Field("foo".to_string()), &json!(123)).unwrap();
        assert_eq!(result, vec![Value::Static(StaticNode::Null)]);

        let result = eval(&Filter::Field("foo".to_string()), &json!(null)).unwrap();
        assert_eq!(result, vec![Value::Static(StaticNode::Null)]);

        let result = eval(&Filter::Field("foo".to_string()), &json!([1, 2, 3])).unwrap();
        assert_eq!(result, vec![Value::Static(StaticNode::Null)]);
    }

    #[test]
    fn test_nested_field() {
        let value = json!({"user": {"name": "alice", "address": {"city": "NYC"}}});
        let filter = Filter::Pipe(
            Box::new(Filter::Field("user".to_string())),
            Box::new(Filter::Field("name".to_string())),
        );
        let result = eval(&filter, &value).unwrap();
        assert_eq!(result, vec![json!("alice")]);
    }

    #[test]
    fn test_deeply_nested_field() {
        let value = json!({"user": {"address": {"city": "NYC"}}});
        let filter = Filter::Pipe(
            Box::new(Filter::Pipe(
                Box::new(Filter::Field("user".to_string())),
                Box::new(Filter::Field("address".to_string())),
            )),
            Box::new(Filter::Field("city".to_string())),
        );
        let result = eval(&filter, &value).unwrap();
        assert_eq!(result, vec![json!("NYC")]);
    }

    #[test]
    fn test_nested_field_missing() {
        let value = json!({"user": {}});
        let filter = Filter::Pipe(
            Box::new(Filter::Field("user".to_string())),
            Box::new(Filter::Field("name".to_string())),
        );
        let result = eval(&filter, &value).unwrap();
        assert_eq!(result, vec![Value::Static(StaticNode::Null)]);
    }

    #[test]
    fn test_field_on_nested_null() {
        let value = json!({"user": null});
        let filter = Filter::Pipe(
            Box::new(Filter::Field("user".to_string())),
            Box::new(Filter::Field("name".to_string())),
        );
        let result = eval(&filter, &value).unwrap();
        assert_eq!(result, vec![Value::Static(StaticNode::Null)]);
    }

    // Index tests
    #[test]
    fn test_index_positive() {
        let value = json!([10, 20, 30]);
        assert_eq!(eval(&Filter::Index(0), &value).unwrap(), vec![json!(10)]);
        assert_eq!(eval(&Filter::Index(1), &value).unwrap(), vec![json!(20)]);
        assert_eq!(eval(&Filter::Index(2), &value).unwrap(), vec![json!(30)]);
    }

    #[test]
    fn test_index_negative() {
        let value = json!([10, 20, 30]);
        assert_eq!(eval(&Filter::Index(-1), &value).unwrap(), vec![json!(30)]);
        assert_eq!(eval(&Filter::Index(-2), &value).unwrap(), vec![json!(20)]);
        assert_eq!(eval(&Filter::Index(-3), &value).unwrap(), vec![json!(10)]);
    }

    #[test]
    fn test_index_out_of_bounds() {
        let value = json!([10, 20, 30]);
        assert_eq!(
            eval(&Filter::Index(10), &value).unwrap(),
            vec![Value::Static(StaticNode::Null)]
        );
        assert_eq!(
            eval(&Filter::Index(-10), &value).unwrap(),
            vec![Value::Static(StaticNode::Null)]
        );
    }

    #[test]
    fn test_index_on_non_array() {
        assert_eq!(
            eval(&Filter::Index(0), &json!({"a": 1})).unwrap(),
            vec![Value::Static(StaticNode::Null)]
        );
        assert_eq!(
            eval(&Filter::Index(0), &json!("string")).unwrap(),
            vec![Value::Static(StaticNode::Null)]
        );
        assert_eq!(
            eval(&Filter::Index(0), &json!(123)).unwrap(),
            vec![Value::Static(StaticNode::Null)]
        );
        assert_eq!(
            eval(&Filter::Index(0), &json!(null)).unwrap(),
            vec![Value::Static(StaticNode::Null)]
        );
    }

    // Iterate tests
    #[test]
    fn test_iterate_array() {
        let value = json!([1, 2, 3]);
        let result = eval(&Filter::Iterate, &value).unwrap();
        assert_eq!(result, vec![json!(1), json!(2), json!(3)]);
    }

    #[test]
    fn test_iterate_object() {
        let value = json!({"a": 1, "b": 2});
        let result = eval(&Filter::Iterate, &value).unwrap();
        // Object iteration returns values (order may vary, so just check contents)
        assert_eq!(result.len(), 2);
        assert!(result.contains(&json!(1)));
        assert!(result.contains(&json!(2)));
    }

    #[test]
    fn test_iterate_empty_array() {
        let value = json!([]);
        let result = eval(&Filter::Iterate, &value).unwrap();
        assert_eq!(result, Vec::<Value>::new());
    }

    #[test]
    fn test_iterate_empty_object() {
        let value = json!({});
        let result = eval(&Filter::Iterate, &value).unwrap();
        assert_eq!(result, Vec::<Value>::new());
    }

    #[test]
    fn test_iterate_non_iterable_errors() {
        assert!(matches!(
            eval(&Filter::Iterate, &json!("string")),
            Err(EvalError::CannotIterate { .. })
        ));
        assert!(matches!(
            eval(&Filter::Iterate, &json!(123)),
            Err(EvalError::CannotIterate { .. })
        ));
        assert!(matches!(
            eval(&Filter::Iterate, &json!(null)),
            Err(EvalError::CannotIterate { .. })
        ));
        assert!(matches!(
            eval(&Filter::Iterate, &json!(true)),
            Err(EvalError::CannotIterate { .. })
        ));
    }

    // Chaining tests
    #[test]
    fn test_chain_field_index() {
        let value = json!({"items": [1, 2, 3]});
        let filter = Filter::Pipe(
            Box::new(Filter::Field("items".to_string())),
            Box::new(Filter::Index(0)),
        );
        assert_eq!(eval(&filter, &value).unwrap(), vec![json!(1)]);
    }

    #[test]
    fn test_chain_index_field() {
        let value = json!([{"id": 1}, {"id": 2}]);
        let filter = Filter::Pipe(
            Box::new(Filter::Index(0)),
            Box::new(Filter::Field("id".to_string())),
        );
        assert_eq!(eval(&filter, &value).unwrap(), vec![json!(1)]);
    }

    #[test]
    fn test_chain_iterate_field() {
        let value = json!({"items": [{"id": 1}, {"id": 2}]});
        let filter = Filter::Pipe(
            Box::new(Filter::Pipe(
                Box::new(Filter::Field("items".to_string())),
                Box::new(Filter::Iterate),
            )),
            Box::new(Filter::Field("id".to_string())),
        );
        assert_eq!(eval(&filter, &value).unwrap(), vec![json!(1), json!(2)]);
    }

    // Quoted field tests
    #[test]
    fn test_quoted_field_special_chars() {
        let value = json!({"foo-bar": 1, "with space": 2});
        assert_eq!(
            eval(&Filter::Field("foo-bar".to_string()), &value).unwrap(),
            vec![json!(1)]
        );
        assert_eq!(
            eval(&Filter::Field("with space".to_string()), &value).unwrap(),
            vec![json!(2)]
        );
    }

    #[test]
    fn test_quoted_field_empty() {
        let value = json!({"": 42});
        assert_eq!(
            eval(&Filter::Field("".to_string()), &value).unwrap(),
            vec![json!(42)]
        );
    }

    #[test]
    fn test_quoted_field_unicode() {
        let value = json!({"日本語": "Japanese"});
        assert_eq!(
            eval(&Filter::Field("日本語".to_string()), &value).unwrap(),
            vec![json!("Japanese")]
        );
    }

    // Explicit pipe tests (verifies eval handles parsed explicit pipes correctly)
    #[test]
    fn test_pipe_explicit() {
        let value = json!({"users": [{"name": "alice"}, {"name": "bob"}]});
        // .users | .[] | .name
        let filter = Filter::Pipe(
            Box::new(Filter::Pipe(
                Box::new(Filter::Field("users".to_string())),
                Box::new(Filter::Iterate),
            )),
            Box::new(Filter::Field("name".to_string())),
        );
        assert_eq!(
            eval(&filter, &value).unwrap(),
            vec![json!("alice"), json!("bob")]
        );
    }

    // Optional access tests
    #[test]
    fn test_optional_iterate_on_non_iterable() {
        // .[]? on a string returns empty (suppresses error)
        let filter = Filter::Optional(Box::new(Filter::Iterate));
        let result = eval(&filter, &json!("not an array")).unwrap();
        assert_eq!(result, Vec::<Value>::new());
    }

    #[test]
    fn test_optional_iterate_on_array() {
        // .[]? on an array works normally
        let filter = Filter::Optional(Box::new(Filter::Iterate));
        let result = eval(&filter, &json!([1, 2, 3])).unwrap();
        assert_eq!(result, vec![json!(1), json!(2), json!(3)]);
    }

    #[test]
    fn test_optional_field_succeeds() {
        // .foo? on an object with foo returns the value
        let filter = Filter::Optional(Box::new(Filter::Field("foo".to_string())));
        let result = eval(&filter, &json!({"foo": "bar"})).unwrap();
        assert_eq!(result, vec![json!("bar")]);
    }

    // Slice tests
    #[test]
    fn test_slice_both_indices() {
        let filter = Filter::Slice(Some(1), Some(3));
        let result = eval(&filter, &json!([0, 1, 2, 3, 4])).unwrap();
        assert_eq!(result, vec![json!([1, 2])]);
    }

    #[test]
    fn test_slice_start_only() {
        let filter = Filter::Slice(Some(2), None);
        let result = eval(&filter, &json!([0, 1, 2, 3, 4])).unwrap();
        assert_eq!(result, vec![json!([2, 3, 4])]);
    }

    #[test]
    fn test_slice_end_only() {
        let filter = Filter::Slice(None, Some(3));
        let result = eval(&filter, &json!([0, 1, 2, 3, 4])).unwrap();
        assert_eq!(result, vec![json!([0, 1, 2])]);
    }

    #[test]
    fn test_slice_negative_end() {
        let filter = Filter::Slice(None, Some(-1));
        let result = eval(&filter, &json!([0, 1, 2, 3, 4])).unwrap();
        assert_eq!(result, vec![json!([0, 1, 2, 3])]);
    }

    #[test]
    fn test_slice_negative_start() {
        let filter = Filter::Slice(Some(-2), None);
        let result = eval(&filter, &json!([0, 1, 2, 3, 4])).unwrap();
        assert_eq!(result, vec![json!([3, 4])]);
    }

    #[test]
    fn test_slice_both_negative() {
        let filter = Filter::Slice(Some(-3), Some(-1));
        let result = eval(&filter, &json!([0, 1, 2, 3, 4])).unwrap();
        assert_eq!(result, vec![json!([2, 3])]);
    }

    #[test]
    fn test_slice_empty_result() {
        let filter = Filter::Slice(Some(3), Some(1));
        let result = eval(&filter, &json!([0, 1, 2, 3, 4])).unwrap();
        assert_eq!(result, vec![json!([])]);
    }

    #[test]
    fn test_slice_string() {
        let filter = Filter::Slice(Some(1), Some(4));
        let result = eval(&filter, &json!("hello")).unwrap();
        assert_eq!(result, vec![json!("ell")]);
    }

    #[test]
    fn test_slice_on_non_array() {
        let filter = Filter::Slice(Some(0), Some(2));
        let result = eval(&filter, &json!(123)).unwrap();
        assert_eq!(result, vec![Value::Static(StaticNode::Null)]);
    }

    // map() tests
    #[test]
    fn test_map_field_access() {
        // map(.a) on [{a:1}, {a:2}] → [1, 2]
        let filter = Filter::Function(FunctionCall::Map(Box::new(Filter::Field("a".to_string()))));
        let result = eval(&filter, &json!([{"a": 1}, {"a": 2}])).unwrap();
        assert_eq!(result, vec![json!([1, 2])]);
    }

    #[test]
    fn test_map_identity() {
        // map(.) on [1,2,3] → [1,2,3]
        let filter = Filter::Function(FunctionCall::Map(Box::new(Filter::Identity)));
        let result = eval(&filter, &json!([1, 2, 3])).unwrap();
        assert_eq!(result, vec![json!([1, 2, 3])]);
    }

    #[test]
    fn test_map_on_empty_array() {
        let filter = Filter::Function(FunctionCall::Map(Box::new(Filter::Field("x".to_string()))));
        let result = eval(&filter, &json!([])).unwrap();
        assert_eq!(result, vec![json!([])]);
    }

    #[test]
    fn test_map_on_non_array_fails() {
        let filter = Filter::Function(FunctionCall::Map(Box::new(Filter::Identity)));
        let result = eval(&filter, &json!({"a": 1}));
        assert!(matches!(result, Err(EvalError::TypeError { .. })));
    }

    #[test]
    fn test_map_with_iterate() {
        // map(.[]) on [[1,2], [3,4]] → [1,2,3,4]
        let filter = Filter::Function(FunctionCall::Map(Box::new(Filter::Iterate)));
        let result = eval(&filter, &json!([[1, 2], [3, 4]])).unwrap();
        assert_eq!(result, vec![json!([1, 2, 3, 4])]);
    }

    // select() tests
    #[test]
    fn test_select_true() {
        // select(.active) with {active: true} → outputs value
        let filter = Filter::Function(FunctionCall::Select(Box::new(Filter::Field(
            "active".to_string(),
        ))));
        let value = json!({"active": true, "name": "test"});
        let result = eval(&filter, &value).unwrap();
        assert_eq!(result, vec![value]);
    }

    #[test]
    fn test_select_false() {
        // select(.active) with {active: false} → no output
        let filter = Filter::Function(FunctionCall::Select(Box::new(Filter::Field(
            "active".to_string(),
        ))));
        let result = eval(&filter, &json!({"active": false})).unwrap();
        assert_eq!(result, Vec::<Value>::new());
    }

    #[test]
    fn test_select_null() {
        // select(.active) with {active: null} → no output
        let filter = Filter::Function(FunctionCall::Select(Box::new(Filter::Field(
            "active".to_string(),
        ))));
        let result = eval(&filter, &json!({"active": null})).unwrap();
        assert_eq!(result, Vec::<Value>::new());
    }

    #[test]
    fn test_select_truthy_number() {
        // select(.) with 0 → outputs (numbers are truthy in jq)
        let filter = Filter::Function(FunctionCall::Select(Box::new(Filter::Identity)));
        let result = eval(&filter, &json!(0)).unwrap();
        assert_eq!(result, vec![json!(0)]);
    }

    #[test]
    fn test_select_truthy_empty_string() {
        // select(.) with "" → outputs (empty string is truthy in jq)
        let filter = Filter::Function(FunctionCall::Select(Box::new(Filter::Identity)));
        let result = eval(&filter, &json!("")).unwrap();
        assert_eq!(result, vec![json!("")]);
    }

    #[test]
    fn test_select_truthy_empty_array() {
        // select(.) with [] → outputs (empty array is truthy in jq)
        let filter = Filter::Function(FunctionCall::Select(Box::new(Filter::Identity)));
        let result = eval(&filter, &json!([])).unwrap();
        assert_eq!(result, vec![json!([])]);
    }

    #[test]
    fn test_select_in_pipe_with_iterate() {
        // .[] | select(.x) filters array elements
        let filter = Filter::Pipe(
            Box::new(Filter::Iterate),
            Box::new(Filter::Function(FunctionCall::Select(Box::new(
                Filter::Field("x".to_string()),
            )))),
        );
        let result = eval(&filter, &json!([{"x": true}, {"x": false}, {"x": true}])).unwrap();
        assert_eq!(result, vec![json!({"x": true}), json!({"x": true})]);
    }

    // sort_by() tests
    #[test]
    fn test_sort_by_field() {
        let filter = Filter::Function(FunctionCall::SortBy(Box::new(Filter::Field(
            "age".to_string(),
        ))));
        let input = json!([{"age": 30, "name": "alice"}, {"age": 20, "name": "bob"}, {"age": 25, "name": "charlie"}]);
        let result = eval(&filter, &input).unwrap();
        assert_eq!(
            result,
            vec![json!([
                {"age": 20, "name": "bob"},
                {"age": 25, "name": "charlie"},
                {"age": 30, "name": "alice"}
            ])]
        );
    }

    #[test]
    fn test_sort_by_empty_array() {
        let filter = Filter::Function(FunctionCall::SortBy(Box::new(Filter::Field(
            "x".to_string(),
        ))));
        let result = eval(&filter, &json!([])).unwrap();
        assert_eq!(result, vec![json!([])]);
    }

    #[test]
    fn test_sort_by_on_non_array_fails() {
        let filter = Filter::Function(FunctionCall::SortBy(Box::new(Filter::Identity)));
        let result = eval(&filter, &json!({"a": 1}));
        assert!(matches!(result, Err(EvalError::TypeError { .. })));
    }

    // group_by() tests
    #[test]
    fn test_group_by_field() {
        let filter = Filter::Function(FunctionCall::GroupBy(Box::new(Filter::Field(
            "type".to_string(),
        ))));
        let input = json!([
            {"type": "a", "v": 1},
            {"type": "b", "v": 2},
            {"type": "a", "v": 3}
        ]);
        let result = eval(&filter, &input).unwrap();
        assert_eq!(
            result,
            vec![json!([
                [{"type": "a", "v": 1}, {"type": "a", "v": 3}],
                [{"type": "b", "v": 2}]
            ])]
        );
    }

    #[test]
    fn test_group_by_empty_array() {
        let filter = Filter::Function(FunctionCall::GroupBy(Box::new(Filter::Field(
            "x".to_string(),
        ))));
        let result = eval(&filter, &json!([])).unwrap();
        assert_eq!(result, vec![json!([])]);
    }

    // unique_by() tests
    #[test]
    fn test_unique_by_field() {
        let filter = Filter::Function(FunctionCall::UniqueBy(Box::new(Filter::Field(
            "id".to_string(),
        ))));
        let input = json!([
            {"id": 1, "v": "a"},
            {"id": 2, "v": "b"},
            {"id": 1, "v": "c"}
        ]);
        let result = eval(&filter, &input).unwrap();
        assert_eq!(
            result,
            vec![json!([{"id": 1, "v": "a"}, {"id": 2, "v": "b"}])]
        );
    }

    #[test]
    fn test_unique_by_preserves_first() {
        // Should keep the first occurrence
        let filter = Filter::Function(FunctionCall::UniqueBy(Box::new(Filter::Field(
            "k".to_string(),
        ))));
        let input = json!([{"k": "x", "n": 1}, {"k": "x", "n": 2}, {"k": "x", "n": 3}]);
        let result = eval(&filter, &input).unwrap();
        assert_eq!(result, vec![json!([{"k": "x", "n": 1}])]);
    }

    // min_by() tests
    #[test]
    fn test_min_by_field() {
        let filter = Filter::Function(FunctionCall::MinBy(Box::new(Filter::Field(
            "age".to_string(),
        ))));
        let input = json!([{"age": 30}, {"age": 20}, {"age": 25}]);
        let result = eval(&filter, &input).unwrap();
        assert_eq!(result, vec![json!({"age": 20})]);
    }

    #[test]
    fn test_min_by_empty_array() {
        let filter = Filter::Function(FunctionCall::MinBy(Box::new(Filter::Field(
            "x".to_string(),
        ))));
        let result = eval(&filter, &json!([])).unwrap();
        assert_eq!(result, vec![Value::Static(StaticNode::Null)]);
    }

    // max_by() tests
    #[test]
    fn test_max_by_field() {
        let filter = Filter::Function(FunctionCall::MaxBy(Box::new(Filter::Field(
            "score".to_string(),
        ))));
        let input = json!([{"score": 10}, {"score": 50}, {"score": 30}]);
        let result = eval(&filter, &input).unwrap();
        assert_eq!(result, vec![json!({"score": 50})]);
    }

    #[test]
    fn test_max_by_empty_array() {
        let filter = Filter::Function(FunctionCall::MaxBy(Box::new(Filter::Field(
            "x".to_string(),
        ))));
        let result = eval(&filter, &json!([])).unwrap();
        assert_eq!(result, vec![Value::Static(StaticNode::Null)]);
    }

    #[test]
    fn test_max_by_single_element() {
        let filter = Filter::Function(FunctionCall::MaxBy(Box::new(Filter::Field(
            "x".to_string(),
        ))));
        let result = eval(&filter, &json!([{"x": 42}])).unwrap();
        assert_eq!(result, vec![json!({"x": 42})]);
    }

    // if-then-else tests
    #[test]
    fn test_if_then_else_true_condition() {
        let filter = Filter::IfThenElse {
            condition: Box::new(Filter::Literal(json!(true))),
            then_branch: Box::new(Filter::Literal(json!("yes"))),
            else_branch: Box::new(Filter::Literal(json!("no"))),
        };
        assert_eq!(eval(&filter, &json!(null)).unwrap(), vec![json!("yes")]);
    }

    #[test]
    fn test_if_then_else_false_condition() {
        let filter = Filter::IfThenElse {
            condition: Box::new(Filter::Literal(json!(false))),
            then_branch: Box::new(Filter::Literal(json!("yes"))),
            else_branch: Box::new(Filter::Literal(json!("no"))),
        };
        assert_eq!(eval(&filter, &json!(null)).unwrap(), vec![json!("no")]);
    }

    #[test]
    fn test_if_then_else_null_is_falsy() {
        let filter = Filter::IfThenElse {
            condition: Box::new(Filter::Literal(json!(null))),
            then_branch: Box::new(Filter::Literal(json!("yes"))),
            else_branch: Box::new(Filter::Literal(json!("no"))),
        };
        assert_eq!(eval(&filter, &json!(null)).unwrap(), vec![json!("no")]);
    }

    #[test]
    fn test_if_then_else_zero_is_truthy() {
        let filter = Filter::IfThenElse {
            condition: Box::new(Filter::Literal(json!(0))),
            then_branch: Box::new(Filter::Literal(json!("yes"))),
            else_branch: Box::new(Filter::Literal(json!("no"))),
        };
        assert_eq!(eval(&filter, &json!(null)).unwrap(), vec![json!("yes")]);
    }

    // Alternative operator tests
    #[test]
    fn test_alternative_left_null() {
        let filter = Filter::Alternative(
            Box::new(Filter::Literal(json!(null))),
            Box::new(Filter::Literal(json!("default"))),
        );
        assert_eq!(eval(&filter, &json!(null)).unwrap(), vec![json!("default")]);
    }

    #[test]
    fn test_alternative_left_false() {
        let filter = Filter::Alternative(
            Box::new(Filter::Literal(json!(false))),
            Box::new(Filter::Literal(json!("default"))),
        );
        assert_eq!(eval(&filter, &json!(null)).unwrap(), vec![json!("default")]);
    }

    #[test]
    fn test_alternative_left_truthy() {
        let filter = Filter::Alternative(
            Box::new(Filter::Literal(json!("value"))),
            Box::new(Filter::Literal(json!("default"))),
        );
        assert_eq!(eval(&filter, &json!(null)).unwrap(), vec![json!("value")]);
    }

    #[test]
    fn test_alternative_left_zero_truthy() {
        // 0 is truthy in jq
        let filter = Filter::Alternative(
            Box::new(Filter::Literal(json!(0))),
            Box::new(Filter::Literal(json!("default"))),
        );
        assert_eq!(eval(&filter, &json!(null)).unwrap(), vec![json!(0)]);
    }

    #[test]
    fn test_alternative_with_field() {
        let filter = Filter::Alternative(
            Box::new(Filter::Field("name".to_string())),
            Box::new(Filter::Literal(json!("unknown"))),
        );
        // Missing field returns null, so alternative kicks in
        assert_eq!(eval(&filter, &json!({})).unwrap(), vec![json!("unknown")]);
        // Present field returns value
        assert_eq!(
            eval(&filter, &json!({"name": "alice"})).unwrap(),
            vec![json!("alice")]
        );
    }

    // has() tests
    #[test]
    fn test_has_present_key() {
        let filter = Filter::Function(FunctionCall::Has("name".to_string()));
        assert_eq!(
            eval(&filter, &json!({"name": "alice"})).unwrap(),
            vec![json!(true)]
        );
    }

    #[test]
    fn test_has_missing_key() {
        let filter = Filter::Function(FunctionCall::Has("name".to_string()));
        assert_eq!(
            eval(&filter, &json!({"age": 30})).unwrap(),
            vec![json!(false)]
        );
    }

    #[test]
    fn test_has_null_value() {
        // has returns true even if value is null
        let filter = Filter::Function(FunctionCall::Has("name".to_string()));
        assert_eq!(
            eval(&filter, &json!({"name": null})).unwrap(),
            vec![json!(true)]
        );
    }

    #[test]
    fn test_has_on_non_object() {
        let filter = Filter::Function(FunctionCall::Has("x".to_string()));
        assert_eq!(eval(&filter, &json!("string")).unwrap(), vec![json!(false)]);
        assert_eq!(eval(&filter, &json!(123)).unwrap(), vec![json!(false)]);
    }

    // Phase 5: String functions
    #[test]
    fn test_split_basic() {
        let filter = Filter::Function(FunctionCall::Split("/".to_string()));
        assert_eq!(
            eval(&filter, &json!("a/b/c")).unwrap(),
            vec![json!(["a", "b", "c"])]
        );
    }

    #[test]
    fn test_split_empty_delim() {
        let filter = Filter::Function(FunctionCall::Split("".to_string()));
        assert_eq!(
            eval(&filter, &json!("hello")).unwrap(),
            vec![json!(["h", "e", "l", "l", "o"])]
        );
    }

    #[test]
    fn test_split_empty_string() {
        let filter = Filter::Function(FunctionCall::Split("/".to_string()));
        assert_eq!(eval(&filter, &json!("")).unwrap(), vec![json!([])]);
    }

    #[test]
    fn test_join_basic() {
        let filter = Filter::Function(FunctionCall::Join("-".to_string()));
        assert_eq!(
            eval(&filter, &json!(["a", "b", "c"])).unwrap(),
            vec![json!("a-b-c")]
        );
    }

    #[test]
    fn test_join_empty_array() {
        let filter = Filter::Function(FunctionCall::Join("-".to_string()));
        assert_eq!(eval(&filter, &json!([])).unwrap(), vec![json!("")]);
    }

    #[test]
    fn test_join_with_null() {
        let filter = Filter::Function(FunctionCall::Join("-".to_string()));
        assert_eq!(
            eval(&filter, &json!(["a", null, "b"])).unwrap(),
            vec![json!("a--b")]
        );
    }

    #[test]
    fn test_startswith_true() {
        let filter = Filter::Function(FunctionCall::StartsWith("hello".to_string()));
        assert_eq!(
            eval(&filter, &json!("hello world")).unwrap(),
            vec![json!(true)]
        );
    }

    #[test]
    fn test_startswith_false() {
        let filter = Filter::Function(FunctionCall::StartsWith("world".to_string()));
        assert_eq!(
            eval(&filter, &json!("hello world")).unwrap(),
            vec![json!(false)]
        );
    }

    #[test]
    fn test_endswith_true() {
        let filter = Filter::Function(FunctionCall::EndsWith(".json".to_string()));
        assert_eq!(
            eval(&filter, &json!("file.json")).unwrap(),
            vec![json!(true)]
        );
    }

    #[test]
    fn test_endswith_false() {
        let filter = Filter::Function(FunctionCall::EndsWith(".json".to_string()));
        assert_eq!(
            eval(&filter, &json!("file.txt")).unwrap(),
            vec![json!(false)]
        );
    }

    #[test]
    fn test_contains_string() {
        let filter = Filter::Function(FunctionCall::Contains(Box::new(Filter::Literal(json!(
            "wor"
        )))));
        assert_eq!(
            eval(&filter, &json!("hello world")).unwrap(),
            vec![json!(true)]
        );
    }

    #[test]
    fn test_contains_string_false() {
        let filter = Filter::Function(FunctionCall::Contains(Box::new(Filter::Literal(json!(
            "xyz"
        )))));
        assert_eq!(eval(&filter, &json!("hello")).unwrap(), vec![json!(false)]);
    }

    #[test]
    fn test_contains_array_single() {
        let filter = Filter::Function(FunctionCall::Contains(Box::new(Filter::Array(vec![
            Filter::Literal(json!(2)),
        ]))));
        assert_eq!(eval(&filter, &json!([1, 2, 3])).unwrap(), vec![json!(true)]);
    }

    #[test]
    fn test_contains_array_multi() {
        let filter = Filter::Function(FunctionCall::Contains(Box::new(Filter::Array(vec![
            Filter::Literal(json!(2)),
            Filter::Literal(json!(3)),
        ]))));
        assert_eq!(eval(&filter, &json!([1, 2, 3])).unwrap(), vec![json!(true)]);
    }

    #[test]
    fn test_contains_array_false() {
        let filter = Filter::Function(FunctionCall::Contains(Box::new(Filter::Array(vec![
            Filter::Literal(json!(4)),
        ]))));
        assert_eq!(
            eval(&filter, &json!([1, 2, 3])).unwrap(),
            vec![json!(false)]
        );
    }

    #[test]
    fn test_contains_object() {
        let filter = Filter::Function(FunctionCall::Contains(Box::new(Filter::Object(vec![(
            ObjectKey::Static("a".to_string()),
            Filter::Literal(json!(1)),
        )]))));
        assert_eq!(
            eval(&filter, &json!({"a": 1, "b": 2})).unwrap(),
            vec![json!(true)]
        );
    }

    #[test]
    fn test_contains_object_false() {
        let filter = Filter::Function(FunctionCall::Contains(Box::new(Filter::Object(vec![(
            ObjectKey::Static("c".to_string()),
            Filter::Literal(json!(3)),
        )]))));
        assert_eq!(
            eval(&filter, &json!({"a": 1, "b": 2})).unwrap(),
            vec![json!(false)]
        );
    }

    // with_entries tests
    #[test]
    fn test_with_entries_identity() {
        let filter = Filter::Function(FunctionCall::WithEntries(Box::new(Filter::Identity)));
        let result = eval(&filter, &json!({"a": 1, "b": 2})).unwrap();
        assert_eq!(result, vec![json!({"a": 1, "b": 2})]);
    }

    #[test]
    fn test_with_entries_select() {
        // with_entries(select(.value > 1)) - keep entries where value > 1
        let filter = Filter::Function(FunctionCall::WithEntries(Box::new(Filter::Function(
            FunctionCall::Select(Box::new(Filter::Compare(
                Box::new(Filter::Field("value".to_string())),
                CompareOp::Gt,
                Box::new(Filter::Literal(json!(1))),
            ))),
        ))));
        let result = eval(&filter, &json!({"a": 1, "b": 2, "c": 3})).unwrap();
        assert_eq!(result, vec![json!({"b": 2, "c": 3})]);
    }

    #[test]
    fn test_with_entries_empty() {
        let filter = Filter::Function(FunctionCall::WithEntries(Box::new(Filter::Identity)));
        let result = eval(&filter, &json!({})).unwrap();
        assert_eq!(result, vec![json!({})]);
    }

    #[test]
    fn test_with_entries_non_object_errors() {
        let filter = Filter::Function(FunctionCall::WithEntries(Box::new(Filter::Identity)));
        assert!(eval(&filter, &json!([1, 2, 3])).is_err());
    }
}
