package programchecker

import (
	"strings"

	"github.com/nexuscrm/kernel/pkg/formula"
	"github.com/nexuscrm/kernel/pkg/formula/spec"
)

type FormulaFunctionSpec = spec.FunctionSpec
type FormulaFunctionDefinition = formula.FunctionDefinition

type FormulaRegistryReader struct {
	registry *formula.ExecutableFunctionRegistry
}

func NewFormulaCatalogReader(registry *formula.ExecutableFunctionRegistry) FormulaRegistryReader {
	return FormulaRegistryReader{registry: registry.Clone()}
}

func NewActiveFormulaCatalogReader() (FormulaRegistryReader, error) {
	registry, err := formula.ActiveRuntimeExecutableFunctionRegistry()
	if err != nil {
		return FormulaRegistryReader{}, err
	}
	return NewFormulaCatalogReader(registry), nil
}

func (r FormulaRegistryReader) FormulaFunction(name string) (FormulaSignature, bool, error) {
	name = strings.TrimSpace(name)
	if name == "" {
		return FormulaSignature{}, false, nil
	}
	registry := r.registry
	if registry == nil {
		var err error
		registry, err = formula.ExecutableFunctionRegistryWithBundles(nil)
		if err != nil {
			return FormulaSignature{}, false, err
		}
	}
	specRegistry := registry.SpecRegistry()
	specDef, ok := lookupFormulaSpec(specRegistry, name)
	if !ok {
		return FormulaSignature{}, false, nil
	}
	def, hasDefinition := lookupFormulaDefinition(registry, name)
	if !hasDefinition {
		return FormulaSignature{Spec: specDef}, true, nil
	}
	return FormulaSignature{Spec: specDef, Definition: &def}, true, nil
}

func (r FormulaRegistryReader) SpecRegistry() *spec.Registry {
	if r.registry == nil {
		return spec.DefaultRegistry().Clone()
	}
	return r.registry.SpecRegistry()
}

func lookupFormulaSpec(registry *spec.Registry, name string) (spec.FunctionSpec, bool) {
	if registry == nil {
		return spec.FunctionSpec{}, false
	}
	if specDef, ok := registry.Lookup(name); ok {
		return specDef, true
	}
	upper := strings.ToUpper(name)
	if upper == name {
		return spec.FunctionSpec{}, false
	}
	return registry.Lookup(upper)
}

func lookupFormulaDefinition(registry *formula.ExecutableFunctionRegistry, name string) (formula.FunctionDefinition, bool) {
	if registry == nil {
		return formula.FunctionDefinition{}, false
	}
	if def, ok := registry.LookupFunctionDefinition(name); ok {
		return def, true
	}
	upper := strings.ToUpper(name)
	if upper == name {
		return formula.FunctionDefinition{}, false
	}
	return registry.LookupFunctionDefinition(upper)
}
