package kas

import (
	"bytes"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"slices"
	"strconv"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/version"
)

// NOTE: the tests in this file ensure the contract between
// the output of the `build/vendor_releases_info.sh` script
// and the expectation of the format and parsing in this module.

var (
	majorMinorRegex = regexp.MustCompile(`^(0|[1-9]\d*)\.(0|[1-9]\d*)$`)
)

func TestReleasesInfo_CorrectFormat(t *testing.T) {
	for _, v := range GitLabReleasesList {
		assert.Regexp(t, majorMinorRegex, v)
	}
}

func TestReleasesInfo_IsSortedDescending(t *testing.T) {
	isSorted := slices.IsSortedFunc(GitLabReleasesList, func(a, b string) int {
		maMajor, maMinor := mustParseMajorMinor(t, a)
		mbMajor, mbMinor := mustParseMajorMinor(t, b)

		if maMajor < mbMajor {
			return 1
		}

		if maMajor > mbMajor {
			return -1
		}

		if maMinor < mbMinor {
			return 1
		}

		if maMinor > mbMinor {
			return -1
		}

		return 0
	})

	assert.True(t, isSorted)
}

func TestReleasesInfo_HasAtLeastSurroundingReleases(t *testing.T) {
	// NOTE: during tests the Version variable is not injected from the VERSION file,
	// thus we just read that file here.
	v, err := version.NewVersion(currentVersion(t))
	require.NoError(t, err)

	idx := slices.Index(GitLabReleasesList, v.MajorMinor)
	require.NotEqual(t, -1, idx)

	assert.GreaterOrEqualf(t, idx, 4, "we need at least 4 newer version in the releases list then the current version. Releases List: %q, Current Version: %q", GitLabReleasesList, v.MajorMinor)
	assert.GreaterOrEqualf(t, len(GitLabReleasesList), idx+4, "we need at least 4 older version in the releases list then the current version. Releases List: %q, Current Version: %q", GitLabReleasesList, v.MajorMinor)
}

func mustParseMajorMinor(t *testing.T, v string) (uint64, uint64) {
	t.Helper()

	m := majorMinorRegex.FindStringSubmatch(v)

	major, err := strconv.ParseUint(m[1], 10, 64)
	require.NoError(t, err)
	minor, err := strconv.ParseUint(m[2], 10, 64)
	require.NoError(t, err)

	return major, minor
}

func currentVersion(t *testing.T) string {
	t.Helper()

	_, filename, _, _ := runtime.Caller(0)
	versionFilePath := filepath.Join(filepath.Dir(filename), "..", "..", "..", "VERSION")
	b, err := os.ReadFile(versionFilePath)
	require.NoError(t, err)
	return string(bytes.Trim(b, " \n"))
}
