package dsl

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/Knetic/govaluate"
)

type dslFunction struct {
	IsCacheable bool
	Name        string
	// if numberOfArgs is defined the signature is automatically generated
	NumberOfArgs       int
	Signatures         []string
	ExpressionFunction govaluate.ExpressionFunction
}

func (d dslFunction) GetSignatures() []string {
	// fixed number of args implies a static signature
	if d.NumberOfArgs > 0 {
		args := make([]string, 0, d.NumberOfArgs)
		for i := 1; i <= d.NumberOfArgs; i++ {
			args = append(args, "arg"+strconv.Itoa(i))
		}
		argsPart := fmt.Sprintf("(%s interface{}) interface{}", strings.Join(args, ", "))
		signature := d.Name + argsPart
		return []string{signature}
	}

	// multi signatures
	var signatures []string
	for _, signature := range d.Signatures {
		signatures = append(signatures, d.Name+signature)
	}

	return signatures
}

func (d dslFunction) Exec(args ...interface{}) (interface{}, error) {
	// fixed number of args implies the possibility to perform matching between the expected number of args and the ones provided
	if d.NumberOfArgs > 0 {
		if len(args) != d.NumberOfArgs {
			signatures := d.GetSignatures()
			if len(signatures) > 0 {
				return nil, fmt.Errorf("%w. correct method signature %q", ErrInvalidDslFunction, signatures[0])
			}
			return nil, ErrInvalidDslFunction
		}
	}

	if !d.IsCacheable {
		return d.ExpressionFunction(args...)
	}

	//functionHash := d.hash()
	//if result, err := resultCache.Get(functionHash); err == nil {
	//	return result, nil
	//}

	result, err := d.ExpressionFunction(args...)
	//if err == nil {
	//	_ = resultCache.Set(functionHash, result)
	//}

	return result, err
}

func (d dslFunction) hash(args ...interface{}) string {
	return fmt.Sprintf(d.Name, args...)
}
