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

// builtin-import.go
package expr

import (
	"io"
	"os"

	"git.portale-stac.it/go-pkg/expr/kern"
	"git.portale-stac.it/go-pkg/expr/scan"
	"git.portale-stac.it/go-pkg/expr/sym"
)

func importFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
	return importGeneral(ctx, name, args)
}

func importAllFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
	CtrlEnable(ctx, kern.ControlExportAll)
	return importGeneral(ctx, name, args)
}

func importGeneral(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
	dirList := buildSearchDirList(ctx, "sources", ENV_EXPR_SOURCE_PATH)
	if v, exists := args[kern.ParamFilepath]; exists && v != nil {
		argv := v.([]any)
		result, err = doImport(ctx, name, dirList, NewArrayIterator(argv))
	}
	return
}

func doImport(ctx kern.ExprContext, name string, dirList []string, it kern.Iterator) (result any, err error) {
	var v any
	var sourceFilepath string

	for v, err = it.Next(); err == nil; v, err = it.Next() {
		if err = checkStringParamExpected(name, v, int(it.Index())); err != nil {
			break
		}
		if sourceFilepath, err = makeFilepath(v.(string), dirList); err != nil {
			break
		}
		var file *os.File
		if file, err = os.Open(sourceFilepath); err == nil {
			defer file.Close()
			var expr *scan.Ast
			scanner := scan.NewScanner(file, scan.DefaultTranslations())
			parser := NewParser()
			if expr, err = parser.parseGeneral(scanner, allowMultiExpr|allowVarRef, sym.SymEos); err == nil {
				result, err = expr.Eval(ctx)
			}
			if err != nil {
				break
			}
		} else {
			break
		}
	}
	if err != nil {
		if err == io.EOF {
			err = nil
		} else {
			result = nil
		}
	}
	return
}

func ImportImportFuncs(ctx kern.ExprContext) {
	ctx.RegisterFunc("import", kern.NewGolangFunctor(importFunc), kern.TypeAny, []kern.ExprFuncParam{
		kern.NewFuncParamFlag(kern.ParamFilepath, kern.PfRepeat),
	})
	ctx.RegisterFunc("importAll", kern.NewGolangFunctor(importAllFunc), kern.TypeAny, []kern.ExprFuncParam{
		kern.NewFuncParamFlag(kern.ParamFilepath, kern.PfRepeat),
	})
}

func init() {
	RegisterBuiltinModule("import", ImportImportFuncs, "Functions import() and include()")
}
