use std::rc::Rc;

use crate::{
    error::{MachineError, ValueConversionError},
    vm::{
        env::Environment,
        value::convert::{AnyFunction, TryFromValue},
    },
};

pub fn load(env: &Rc<Environment>) {
    env.defun_native(
        "apply",
        "Applies the function to a given argument list",
        |vm, env, args| {
            let [f, xs] = args else {
                return Err(MachineError::InvalidArgumentCount);
            };
            let f = AnyFunction::try_from_value(f)?;
            let args = xs
                .proper_iter(MachineError::ValueConversion(ValueConversionError {
                    expected: "proper list".into(),
                    got: xs.clone(),
                }))
                .map(|x| x.cloned())
                .collect::<Result<Vec<_>, _>>()?;
            f.invoke(vm, env, &args[..])
        },
    );
    env.defun_native("identity", "Returns the argument as is", |_, _, args| {
        let [arg] = args else {
            return Err(MachineError::InvalidArgumentCount);
        };
        Ok(arg.clone())
    });
}
