package capver

//go:generate go run ../../tools/capver/main.go

import (
	"maps"
	"slices"
	"sort"
	"strings"

	"tailscale.com/tailcfg"
	"tailscale.com/util/set"
)

// minVersionParts is the minimum number of version parts needed for major.minor.
const minVersionParts = 2

// CanOldCodeBeCleanedUp is called at server startup to panic when
// [MinSupportedCapabilityVersion] has crossed a threshold at which a
// backwards-compat emit path can be deleted. Each entry pairs a
// [tailcfg.CapabilityVersion] threshold with the message identifying
// the code to remove; today there are none.
//
// All capability-version-gated cleanups should be registered here.
func CanOldCodeBeCleanedUp() {
}

func tailscaleVersSorted() []string {
	return slices.Sorted(maps.Keys(tailscaleToCapVer))
}

// TailscaleVersion returns the Tailscale version for the given [tailcfg.CapabilityVersion].
func TailscaleVersion(ver tailcfg.CapabilityVersion) string {
	return capVerToTailscaleVer[ver]
}

// CapabilityVersion returns the [tailcfg.CapabilityVersion] for the given Tailscale version.
// It accepts both full versions (v1.90.1) and minor versions (v1.90).
func CapabilityVersion(ver string) tailcfg.CapabilityVersion {
	if !strings.HasPrefix(ver, "v") {
		ver = "v" + ver
	}

	// Try direct lookup first (works for minor versions like v1.90)
	if cv, ok := tailscaleToCapVer[ver]; ok {
		return cv
	}

	// Try extracting minor version from full version (v1.90.1 -> v1.90)
	parts := strings.Split(strings.TrimPrefix(ver, "v"), ".")
	if len(parts) >= minVersionParts {
		minor := "v" + parts[0] + "." + parts[1]
		return tailscaleToCapVer[minor]
	}

	return 0
}

// TailscaleLatestMajorMinor returns the n latest Tailscale versions (e.g. 1.80).
func TailscaleLatestMajorMinor(n int, stripV bool) []string {
	if n <= 0 {
		return nil
	}

	majors := set.Set[string]{}

	for _, vers := range tailscaleVersSorted() {
		if stripV {
			vers = strings.TrimPrefix(vers, "v")
		}

		v := strings.Split(vers, ".")
		majors.Add(v[0] + "." + v[1])
	}

	majorSl := majors.Slice()
	sort.Strings(majorSl)

	if n > len(majorSl) {
		return majorSl
	}

	return majorSl[len(majorSl)-n:]
}
