// 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 newExprFunctor(e Expr, params []string, ctx ExprContext) *exprFunctor {
// 	return &exprFunctor{expr: e, params: params, defCtx: ctx}
// }

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

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

func (functor *exprFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
	// if functor.defCtx != nil {
	// 	ctx.Merge(functor.defCtx)
	// }

	for i, p := range functor.params {
		if i < len(args) {
			arg := args[i]
			if funcArg, ok := arg.(Functor); ok {
				paramSpecs := funcArg.GetParams()
				ctx.RegisterFunc(p.Name(), funcArg, TypeAny, paramSpecs)
			} else {
				ctx.UnsafeSetVar(p.Name(), arg)
			}
		} else {
			ctx.UnsafeSetVar(p.Name(), nil)
		}
	}
	result, err = functor.expr.Eval(ctx)
	return
}