package task

import (
	"testing"

	"github.com/tidbcloud/infra-provider/regional-server/api/v1alpha1"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
)

func TestBuildServicePorts(t *testing.T) {
	t.Parallel()

	legacyPorts := []corev1.ServicePort{
		{
			Name:       "mysql-client",
			Port:       4000,
			TargetPort: intstr.FromInt32(4000),
			Protocol:   corev1.ProtocolTCP,
		},
	}

	cases := []struct {
		name    string
		spec    v1alpha1.LoadBalancerSpec
		want    []corev1.ServicePort
		wantErr bool
	}{
		{
			name: "legacy single Port preserved byte-for-byte",
			spec: v1alpha1.LoadBalancerSpec{Port: 4000},
			want: legacyPorts,
		},
		{
			name: "new Ports path honors name, targetPort default, TCP default",
			spec: v1alpha1.LoadBalancerSpec{
				Ports: []v1alpha1.LoadBalancerPort{
					{Name: "cassandra", Port: 9042},
					{Name: "cassandra-ssl", Port: 9142, TargetPort: 9142, Protocol: "TCP"},
				},
			},
			want: []corev1.ServicePort{
				{
					Name:       "cassandra",
					Port:       9042,
					TargetPort: intstr.FromInt32(9042),
					Protocol:   corev1.ProtocolTCP,
				},
				{
					Name:       "cassandra-ssl",
					Port:       9142,
					TargetPort: intstr.FromInt32(9142),
					Protocol:   corev1.ProtocolTCP,
				},
			},
		},
		{
			name: "mixed Port + Ports resolves to Ports (Port is ignored)",
			spec: v1alpha1.LoadBalancerSpec{
				Port: 4000,
				Ports: []v1alpha1.LoadBalancerPort{
					{Name: "cassandra", Port: 9042},
				},
			},
			want: []corev1.ServicePort{
				{
					Name:       "cassandra",
					Port:       9042,
					TargetPort: intstr.FromInt32(9042),
					Protocol:   corev1.ProtocolTCP,
				},
			},
		},
		{
			name:    "both Port and Ports empty returns error",
			spec:    v1alpha1.LoadBalancerSpec{},
			wantErr: true,
		},
		{
			name: "multi-port empty Name rejected",
			spec: v1alpha1.LoadBalancerSpec{
				Ports: []v1alpha1.LoadBalancerPort{
					{Name: "cassandra", Port: 9042},
					{Name: "", Port: 9142},
				},
			},
			wantErr: true,
		},
		{
			name: "multi-port duplicate Name rejected",
			spec: v1alpha1.LoadBalancerSpec{
				Ports: []v1alpha1.LoadBalancerPort{
					{Name: "x", Port: 9042},
					{Name: "x", Port: 9142},
				},
			},
			wantErr: true,
		},
		{
			name: "single Port with empty Name accepted",
			spec: v1alpha1.LoadBalancerSpec{
				Ports: []v1alpha1.LoadBalancerPort{{Name: "", Port: 9042}},
			},
			want: []corev1.ServicePort{
				{Name: "", Port: 9042, TargetPort: intstr.FromInt32(9042), Protocol: corev1.ProtocolTCP},
			},
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			got, err := buildServicePorts(&tc.spec)
			if (err != nil) != tc.wantErr {
				t.Fatalf("buildServicePorts() err = %v, wantErr %v", err, tc.wantErr)
			}
			if tc.wantErr {
				return
			}
			if len(got) != len(tc.want) {
				t.Fatalf("buildServicePorts() len = %d, want %d", len(got), len(tc.want))
			}
			for i := range tc.want {
				if got[i] != tc.want[i] {
					t.Fatalf("buildServicePorts()[%d] = %#v, want %#v", i, got[i], tc.want[i])
				}
			}
		})
	}
}

func TestBuildBasicServicePublishNotReadyAddresses(t *testing.T) {
	t.Parallel()

	cases := []struct {
		name                     string
		gracefulUnhealthyEnabled bool
		want                     bool
	}{
		{
			name:                     "disabled by default",
			gracefulUnhealthyEnabled: false,
			want:                     false,
		},
		{
			name:                     "enabled for graceful unhealthy",
			gracefulUnhealthyEnabled: true,
			want:                     true,
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()

			baseTask := &BaseTask{Context: &Context{LoadBalancer: &v1alpha1.LoadBalancer{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "test-lb",
					Namespace: "test-ns",
				},
				Spec: v1alpha1.LoadBalancerSpec{
					Namespace:                "test-ns",
					Type:                     v1alpha1.PrivateLoadBalancerType,
					Port:                     4000,
					GracefulUnhealthyEnabled: tc.gracefulUnhealthyEnabled,
				},
			}}}

			got := baseTask.BuildBasicService().Spec.PublishNotReadyAddresses
			if got != tc.want {
				t.Fatalf("PublishNotReadyAddresses = %t, want %t", got, tc.want)
			}
		})
	}
}
