// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium

package utils

import (
	"fmt"
	"os"
	"regexp"
	"strconv"
	"strings"

	"github.com/blang/semver/v4"
)

var versionRegexp = regexp.MustCompile(`^((v?(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-[a-zA-Z0-9.]+)*|[a-zA-Z0-9-_.@:]*:[a-zA-Z0-9-_.@:]+)|([0-9a-fA-F]{40})|(latest))$`).MatchString

func CheckVersion(version string) error {
	if !versionRegexp(version) && version != "" {
		return fmt.Errorf("invalid syntax %q for image tag", version)
	}
	return nil
}

func ParseCiliumVersion(version string) (semver.Version, error) {
	return semver.ParseTolerant(version)
}

const CLIModeVariableName = "CILIUM_CLI_MODE"

var imageRegexp = regexp.MustCompile(`\A(.*?)(?:(:.*?)(@sha256:[0-9a-f]{64})?)?\z`)

// BuildImagePath builds a fully-qualified image path from the given
// user image and version and default image.
//
// NOTE: Currently 'userVersion' is never passed as an empty string as
// it is defaulted on the CLI interface to the default version.
//
// If 'userVersion' can already contains a colon (':') it is simply
// concatenated with the image string. This is useful for using the
// "latest" image in testing with "--version :latest". Without the
// colon 'userVersion' is always prepended with 'v' if it is missing.
// This is also useful for postfixing the image name with "-ci", for
// example ("--version -ci:4fac771179959ca575eb6f993d566653d3bfa167").
func BuildImagePath(userImage, userVersion, defaultImage, defaultVersion string) string {
	var image string
	switch {
	case userImage == "" && userVersion == "":
		if strings.Contains(defaultVersion, ":") {
			image = defaultImage + defaultVersion
		} else {
			image = defaultImage + ":" + defaultVersion
		}
	case userImage == "" && strings.Contains(userVersion, ":"):
		// userVersion already contains the colon. Useful for ":latest",
		// or for "-ci:<hash>"
		image = defaultImage + userVersion
	case userImage == "" && !strings.HasPrefix(userVersion, "v"):
		image = defaultImage + ":v" + userVersion
	case userImage == "":
		image = defaultImage + ":" + userVersion
	case strings.Contains(userImage, ":"):
		// Fully-qualified userImage?
		image = userImage
	case strings.Contains(userVersion, ":"):
		// ':' in userVersion?
		image = userImage + userVersion
	default:
		image = userImage + ":" + userVersion
	}

	if m := imageRegexp.FindStringSubmatch(image); m != nil {
		image = m[1] + m[2]
	}

	return image
}

// IsInHelmMode returns true if cilium-cli is in "helm" mode. Otherwise, it returns false.
func IsInHelmMode() bool {
	return os.Getenv(CLIModeVariableName) != "classic"
}

func MustParseBool(v string) bool {
	b, err := strconv.ParseBool(v)
	if err != nil {
		panic(fmt.Errorf("failed to parse string [%s] to bool: %s", v, err))
	}
	return b
}
