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

// import-utils.go
package expr

import (
	"errors"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"strings"

	"git.portale-stac.it/go-pkg/expr/kern"
	"git.portale-stac.it/go-pkg/expr/types/str"
	"git.portale-stac.it/go-pkg/expr/util"
)

const (
	ENV_EXPR_SOURCE_PATH = "EXPR_PATH"
	ENV_EXPR_PLUGIN_PATH = "EXPR_PLUGIN_PATH"
)

func checkStringParamExpected(funcName string, paramValue any, paramPos int) (err error) {
	if !(str.IsString(paramValue) /*|| isArray(paramValue)*/) {
		err = fmt.Errorf("%s(): param nr %d has wrong type %s, string expected", funcName, paramPos+1, kern.TypeName(paramValue))
	}
	return
}

// func addSourceEnvImportDirs(varName string, dirList []string) []string {
// 	return addEnvImportDirs(ENV_EXPR_SOURCE_PATH, dirList)
// }

// func addPluginEnvImportDirs(varName string, dirList []string) []string {
// 	return addEnvImportDirs(ENV_EXPR_PLUGIN_PATH, dirList)
// }

func addEnvImportDirs(envVarName string, dirList []string) []string {
	if dirSpec, exists := os.LookupEnv(envVarName); exists {
		dirs := strings.Split(dirSpec, ":")
		if dirList == nil {
			dirList = dirs
		} else {
			dirList = append(dirList, dirs...)
		}
	}
	return dirList
}

func addSearchDirs(ctx kern.ExprContext, endingPath string, dirList []string) []string {
	if dirSpec, exists := getControlString(ctx, kern.ControlSearchPath); exists {
		dirs := strings.Split(dirSpec, ":")
		if dirList == nil {
			dirList = dirs
		} else {
			if len(endingPath) > 0 {
				for _, d := range dirs {
					dirList = append(dirList, path.Join(d, endingPath))
				}
			} else {
				dirList = append(dirList, dirs...)
			}
		}
	}
	return dirList
}

func buildSearchDirList(ctx kern.ExprContext, endingPath, envVarName string) (dirList []string) {
	dirList = addEnvImportDirs(envVarName, dirList)
	dirList = addSearchDirs(ctx, endingPath, dirList)
	return
}

func isFile(filePath string) bool {
	info, err := os.Stat(filePath)
	return (err == nil || errors.Is(err, os.ErrExist)) && info.Mode().IsRegular()
}

func searchAmongPath(filename string, dirList []string) (filePath string) {
	var err error

	suffix := SHAREDLIBRARY_EXTENSION
	if strings.HasSuffix(filename, ".debug") {
		suffix += ".debug"
	}

	for _, dir := range dirList {
		if dir, err = util.ExpandPath(dir); err != nil {
			continue
		}
		fullPath := path.Join(dir, filename)
		if isFile(fullPath) {
			filePath = fullPath
			break
		}

		// subdir := strings.TrimSuffix(filename, suffix)
		// if fullPath := path.Join(dir, subdir, filename); isFile(fullPath) {
		// 	filePath = fullPath
		// 	break
		// }
	}
	return
}

func isPathRelative(filePath string) bool {
	unixPath := filepath.ToSlash(filePath)
	return strings.HasPrefix(unixPath, "./") || strings.HasPrefix(unixPath, "../")
}

func makeFilepath(filename string, dirList []string) (filePath string, err error) {
	if filename, err = util.ExpandPath(filename); err != nil {
		return
	}

	if path.IsAbs(filename) || isPathRelative(filename) {
		if isFile(filename) {
			filePath = filename
		}
	} else {
		filePath = searchAmongPath(filename, dirList)
	}
	if len(filePath) == 0 {
		err = fmt.Errorf("file %q not found", filename)
	}
	return
}
