package router

import (
	"context"
	"slices"
	"testing"

	"github.com/stretchr/testify/assert"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/api"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/testing/testhelpers"
	"gitlab.com/gitlab-org/cluster-integration/tunnel/tool/grpcz"
	"gitlab.com/gitlab-org/cluster-integration/tunnel/tunserver"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/client-go/kubernetes/fake"
)

var (
	_ tunserver.PollingGatewayURLQuerier[grpcz.URLTarget, api.AgentKey] = (*GatewayURLQuerier)(nil)
)

const (
	ns = "test-ns"
)

func TestGatewayURLQuerier(t *testing.T) {
	readyConds := []corev1.PodCondition{
		{
			Type:   corev1.PodReady,
			Status: corev1.ConditionTrue,
		},
	}
	c := fake.NewSimpleClientset(
		// Ready pod but invalid namespace
		&corev1.Pod{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "pod1",
				Namespace: "some-ns",
			},
			Status: corev1.PodStatus{
				Phase:      corev1.PodRunning,
				Conditions: readyConds,
				PodIP:      "1.0.0.1",
			},
		},
		// Ready 1!
		&corev1.Pod{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "pod2",
				Namespace: ns,
			},
			Status: corev1.PodStatus{
				Phase:      corev1.PodRunning,
				Conditions: readyConds,
				PodIP:      "1.0.0.2",
			},
		},
		// Pending with ready conditions (to test filtering)
		&corev1.Pod{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "pod3",
				Namespace: ns,
			},
			Status: corev1.PodStatus{
				Phase:      corev1.PodPending,
				Conditions: readyConds,
				PodIP:      "1.0.0.2",
			},
		},
		// Running without ready conditions (to test filtering)
		&corev1.Pod{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "pod4",
				Namespace: ns,
			},
			Status: corev1.PodStatus{
				Phase: corev1.PodRunning,
				PodIP: "1.0.0.3",
			},
		},
		// Running and ready but without IP (to test filtering)
		&corev1.Pod{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "pod5",
				Namespace: ns,
			},
			Status: corev1.PodStatus{
				Phase:      corev1.PodRunning,
				Conditions: readyConds,
				PodIP:      "", // no IP
			},
		},
		// Ready 2!
		&corev1.Pod{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "pod6",
				Namespace: ns,
			},
			Status: corev1.PodStatus{
				Phase:      corev1.PodRunning,
				Conditions: readyConds,
				PodIP:      "2.0.0.1",
			},
		},
		// Ready 3, IPv6!
		&corev1.Pod{
			ObjectMeta: metav1.ObjectMeta{
				Name:      "pod7",
				Namespace: ns,
			},
			Status: corev1.PodStatus{
				Phase:      corev1.PodRunning,
				Conditions: readyConds,
				PodIP:      "fa01:c056:2d1a:9a9c:9d25:2199:dd8a:0b42",
			},
		},
	)

	q := NewGatewayURLQuerier(c, ns, "", "grpc", "80")

	var wg wait.Group
	defer wg.Wait()
	ctx, cancel := context.WithCancel(t.Context())
	defer cancel()

	wg.Start(func() {
		assert.NoError(t, q.Run(ctx))
	})

	pollCtx, pollCancel := context.WithCancel(context.Background())
	defer pollCancel()
	q.PollGatewayURLs(pollCtx, testhelpers.AgentkKey1, func(gatewayURLs []grpcz.URLTarget) {
		slices.Sort(gatewayURLs)
		expectedURLs := []grpcz.URLTarget{"grpc://1.0.0.2:80", "grpc://2.0.0.1:80", "grpc://[fa01:c056:2d1a:9a9c:9d25:2199:dd8a:0b42]:80"}
		assert.Equal(t, expectedURLs, gatewayURLs)
		pollCancel()
	})
}
