package mutatefuncs

import (
	"testing"

	"github.com/stretchr/testify/assert"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/util/intstr"
)

func TestUpsertServicePort(t *testing.T) {
	tests := []struct {
		name     string
		target   *corev1.Service
		port     corev1.ServicePort
		expected []corev1.ServicePort
	}{
		{
			name: "add new port when target has no ports",
			target: &corev1.Service{
				Spec: corev1.ServiceSpec{
					Ports: []corev1.ServicePort{},
				},
			},
			port: corev1.ServicePort{
				Name:       "http",
				Port:       80,
				TargetPort: intstr.FromInt(8080),
				Protocol:   corev1.ProtocolTCP,
			},
			expected: []corev1.ServicePort{
				{
					Name:       "http",
					Port:       80,
					TargetPort: intstr.FromInt(8080),
					Protocol:   corev1.ProtocolTCP,
				},
			},
		},
		{
			name: "update existing port with same port number",
			target: &corev1.Service{
				Spec: corev1.ServiceSpec{
					Ports: []corev1.ServicePort{
						{
							Name:       "old-http",
							Port:       80,
							TargetPort: intstr.FromInt(9090),
							Protocol:   corev1.ProtocolUDP,
						},
					},
				},
			},
			port: corev1.ServicePort{
				Name:       "new-http",
				Port:       80,
				TargetPort: intstr.FromInt(8080),
				Protocol:   corev1.ProtocolTCP,
			},
			expected: []corev1.ServicePort{
				{
					Name:       "new-http",
					Port:       80,
					TargetPort: intstr.FromInt(8080),
					Protocol:   corev1.ProtocolTCP,
				},
			},
		},
		{
			name: "add new port when target has different port number",
			target: &corev1.Service{
				Spec: corev1.ServiceSpec{
					Ports: []corev1.ServicePort{
						{
							Name:       "http",
							Port:       80,
							TargetPort: intstr.FromInt(8080),
							Protocol:   corev1.ProtocolTCP,
						},
					},
				},
			},
			port: corev1.ServicePort{
				Name:       "https",
				Port:       443,
				TargetPort: intstr.FromInt(8443),
				Protocol:   corev1.ProtocolTCP,
			},
			expected: []corev1.ServicePort{
				{
					Name:       "http",
					Port:       80,
					TargetPort: intstr.FromInt(8080),
					Protocol:   corev1.ProtocolTCP,
				},
				{
					Name:       "https",
					Port:       443,
					TargetPort: intstr.FromInt(8443),
					Protocol:   corev1.ProtocolTCP,
				},
			},
		},
		{
			name: "update port with string target port",
			target: &corev1.Service{
				Spec: corev1.ServiceSpec{
					Ports: []corev1.ServicePort{
						{
							Name:       "http",
							Port:       80,
							TargetPort: intstr.FromString("http-port"),
							Protocol:   corev1.ProtocolTCP,
						},
					},
				},
			},
			port: corev1.ServicePort{
				Name:       "http",
				Port:       80,
				TargetPort: intstr.FromString("new-http-port"),
				Protocol:   corev1.ProtocolTCP,
			},
			expected: []corev1.ServicePort{
				{
					Name:       "http",
					Port:       80,
					TargetPort: intstr.FromString("new-http-port"),
					Protocol:   corev1.ProtocolTCP,
				},
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			UpsertServicePort(tt.target, tt.port)
			assert.Equal(t, tt.expected, tt.target.Spec.Ports)
		})
	}
}
