//! Eval implementation for the filter function

use hamelin_lib::func::defs::Filter;

use crate::eval::error::EvalError;
use crate::eval::evaluator::invoke_closure;
use crate::registry::EvalRegistry;
use crate::value::Value;

/// Register the filter function eval implementation.
pub fn register(registry: &mut EvalRegistry) {
    registry.register_eval::<Filter>(|mut bindings| {
        let array_value = bindings.take_by_name("array")?;
        let closure_value = bindings.take_by_name("lambda")?;

        if array_value.is_null() {
            return Ok(Value::Null);
        }

        let elements = array_value.require_array()?;
        let closure = closure_value.require_closure()?;

        let mut results = Vec::new();
        for elem in elements {
            let predicate_result = invoke_closure(&closure, vec![elem.clone()])?;
            match &predicate_result {
                Value::Null => {}
                Value::Boolean(true) => results.push(elem),
                Value::Boolean(false) => {}
                other => {
                    return Err(EvalError::execution(format!(
                        "filter predicate must return boolean, got {}",
                        other.type_name()
                    ))
                    .into());
                }
            }
        }

        Ok(Value::Array(results))
    });
}
