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

// function.go
package expr

import (
	"git.portale-stac.it/go-pkg/expr/kern"
)

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

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

func newExprFunctor(e kern.Expr, params []kern.ExprFuncParam, ctx kern.ExprContext) *exprFunctor {
	var defCtx kern.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() kern.ExprContext {
	return functor.defCtx
}

func (functor *exprFunctor) InvokeNamed(ctx kern.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.(kern.Functor); ok {
				paramSpecs := funcArg.GetParams()
				ctx.RegisterFunc(p.Name(), funcArg, kern.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 = kern.ErrMissingParams(name, missing)
	} else {
		result, err = functor.expr.Eval(ctx)
	}
	return
}
