// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package toolchain

import (
	"io/fs"
	"os"
	"path/filepath"
	"strings"
	"sync"

	"cmd/go/internal/gover"
)

// pathExts is a cached PATHEXT list.
var pathExts struct {
	once sync.Once
	list []string
}

func initPathExts() {
	var exts []string
	x := os.Getenv(`PATHEXT`)
	if x != "" {
		for _, e := range strings.Split(strings.ToLower(x), `;`) {
			if e == "" {
				continue
			}
			if e[0] != '.' {
				e = "." + e
			}
			exts = append(exts, e)
		}
	} else {
		exts = []string{".com", ".exe", ".bat", ".cmd"}
	}
	pathExts.list = exts
}

// pathDirs returns the directories in the system search path.
func pathDirs() []string {
	return filepath.SplitList(os.Getenv("PATH"))
}

// pathVersion returns the Go version implemented by the file
// described by de and info in directory dir.
// The analysis only uses the name itself; it does not run the program.
func pathVersion(dir string, de fs.DirEntry, info fs.FileInfo) (string, bool) {
	pathExts.once.Do(initPathExts)
	name, _, ok := cutExt(de.Name(), pathExts.list)
	if !ok {
		return "", false
	}
	v := gover.FromToolchain(name)
	if v == "" {
		return "", false
	}
	return v, true
}

// cutExt looks for any of the known extensions at the end of file.
// If one is found, cutExt returns the file name with the extension trimmed,
// the extension itself, and true to signal that an extension was found.
// Otherwise cutExt returns file, "", false.
func cutExt(file string, exts []string) (name, ext string, found bool) {
	i := strings.LastIndex(file, ".")
	if i < 0 {
		return file, "", false
	}
	for _, x := range exts {
		if strings.EqualFold(file[i:], x) {
			return file[:i], file[i:], true
		}
	}
	return file, "", false
}
