// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
// All rights reserved.

// function.go
package expr

// ---- Linking with Expr functions
type exprFunctor struct {
	baseFunctor
	params []ExprFuncParam
	expr   Expr
	defCtx ExprContext
}

func (functor *exprFunctor) GetParams() (params []ExprFuncParam) {
	return functor.params
}

func newExprFunctor(e Expr, params []ExprFuncParam, ctx ExprContext) *exprFunctor {
	var defCtx ExprContext
	if ctx != nil {
		defCtx = ctx
	}
	return &exprFunctor{expr: e, params: params, defCtx: defCtx}
}

func (functor *exprFunctor) TypeName() string {
	return "ExprFunctor"
}

func (functor *exprFunctor) GetDefinitionContext() ExprContext {
	return functor.defCtx
}

func (functor *exprFunctor) InvokeNamed(ctx ExprContext, name string, args map[string]any) (result any, err error) {
	var missing []string
	for _, p := range functor.params {
		if arg, exists := args[p.Name()]; exists {
			if funcArg, ok := arg.(Functor); ok {
				paramSpecs := funcArg.GetParams()
				ctx.RegisterFunc(p.Name(), funcArg, TypeAny, paramSpecs)
			} else {
				ctx.UnsafeSetVar(p.Name(), arg)
			}
		} else {
			if missing == nil {
				missing = make([]string, 0, 1)
			}
			missing = append(missing, p.Name())
			// ctx.UnsafeSetVar(p.Name(), nil)
		}
	}
	if missing != nil {
		err = ErrMissingParams(name, missing)
	} else {
		result, err = functor.expr.Eval(ctx)
	}
	return
}