package gkeheterogeneous

import (
	"fmt"
	"testing"

	"github.com/stretchr/testify/require"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
)

func TestRecordComputeClassCleanupCandidate(t *testing.T) {
	cluster := testComputeClassCleanupCluster(map[string]string{}, true)

	require.NoError(t, RecordComputeClassCleanupCandidate(cluster, " priority-a "))
	require.NoError(t, RecordComputeClassCleanupCandidate(cluster, "priority-a"))
	require.NoError(t, RecordComputeClassCleanupCandidate(cluster, "priority-b"))

	candidates, err := ComputeClassCleanupCandidates(cluster)
	require.NoError(t, err)
	require.Equal(t, []string{"priority-a", "priority-b"}, candidates)
}

func TestRecordComputeClassCleanupCandidateSkipsNonGKE(t *testing.T) {
	cluster := testComputeClassCleanupCluster(map[string]string{}, false)

	require.NoError(t, RecordComputeClassCleanupCandidate(cluster, "priority-a"))
	require.NotContains(t, cluster.GetAnnotations(), ComputeClassCleanupCandidatesAnnotationKey)
}

func TestRecordComputeClassCleanupCandidateOverwritesMalformedCandidates(t *testing.T) {
	cluster := testComputeClassCleanupCluster(map[string]string{
		ComputeClassCleanupCandidatesAnnotationKey: "not-json",
	}, true)

	require.NoError(t, RecordComputeClassCleanupCandidate(cluster, "priority-a"))

	candidates, err := ComputeClassCleanupCandidates(cluster)
	require.NoError(t, err)
	require.Equal(t, []string{"priority-a"}, candidates)
}

func TestSetComputeClassCleanupCandidatesDeletesAnnotationWhenEmpty(t *testing.T) {
	cluster := testComputeClassCleanupCluster(map[string]string{}, true)
	require.NoError(t, RecordComputeClassCleanupCandidate(cluster, "priority-a"))

	require.NoError(t, SetComputeClassCleanupCandidates(cluster, nil))
	require.NotContains(t, cluster.GetAnnotations(), ComputeClassCleanupCandidatesAnnotationKey)
}

func TestRecordComputeClassCleanupCandidatePrunesOldCandidates(t *testing.T) {
	cluster := testComputeClassCleanupCluster(map[string]string{}, true)

	for i := 0; i < maxComputeClassCleanupCandidates+5; i++ {
		require.NoError(t, RecordComputeClassCleanupCandidate(cluster, fmt.Sprintf("priority-%02d", i)))
	}

	candidates, err := ComputeClassCleanupCandidates(cluster)
	require.NoError(t, err)
	require.Len(t, candidates, maxComputeClassCleanupCandidates)
	require.Equal(t, "priority-05", candidates[0])
}

func testComputeClassCleanupCluster(annotations map[string]string, gke bool) *cloudv1.Cluster {
	labels := map[string]string{
		cloudv1.TenantTagKey:  "tenant-1",
		cloudv1.ProjectTagKey: "project-1",
	}
	if gke {
		labels[cloudv1.ProviderTypeLabel] = cloudv1.ProviderTypeGKE
	}
	return &cloudv1.Cluster{
		ObjectMeta: metav1.ObjectMeta{
			Name:        "cluster-1",
			Namespace:   "ns-1",
			Labels:      labels,
			Annotations: annotations,
		},
	}
}
