//
// Copyright (c) 2019-2021 Red Hat, Inc.
// This program and the accompanying materials are made
// available under the terms of the Eclipse Public License 2.0
// which is available at https://www.eclipse.org/legal/epl-2.0/
//
// SPDX-License-Identifier: EPL-2.0
//
// Contributors:
//   Red Hat, Inc. - initial API and implementation
//
package deploy

import (
	"context"

	"github.com/stretchr/testify/assert"

	chev2 "github.com/eclipse-che/che-operator/api/v2"
	defaults "github.com/eclipse-che/che-operator/pkg/common/operator-defaults"
	"github.com/eclipse-che/che-operator/pkg/common/test"
	networking "k8s.io/api/networking/v1"
	v1 "k8s.io/api/networking/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/utils/pointer"

	"testing"
)

func TestIngressSpec(t *testing.T) {
	type testCase struct {
		name             string
		ingressName      string
		ingressPath      string
		ingressComponent string
		serviceName      string
		servicePort      int
		expectedIngress  *networking.Ingress
		cheCluster       *chev2.CheCluster
	}

	testCases := []testCase{
		{
			name:        "Test ingress",
			ingressName: "test",
			cheCluster: &chev2.CheCluster{
				ObjectMeta: metav1.ObjectMeta{
					Namespace: "eclipse-che",
					Name:      "eclipse-che",
				},
				Spec: chev2.CheClusterSpec{
					Networking: chev2.CheClusterSpecNetworking{
						Hostname:    "test-host",
						Labels:      map[string]string{"type": "default"},
						Annotations: map[string]string{"annotation-key": "annotation-value"},
					},
				},
			},
			ingressPath:      "",
			ingressComponent: defaults.GetCheFlavor(),
			serviceName:      "che-host",
			servicePort:      8080,
			expectedIngress: &networking.Ingress{
				ObjectMeta: metav1.ObjectMeta{
					Name:      "test",
					Namespace: "eclipse-che",
					Labels: map[string]string{
						"type":                         "default",
						"app.kubernetes.io/component":  defaults.GetCheFlavor(),
						"app.kubernetes.io/instance":   defaults.GetCheFlavor(),
						"app.kubernetes.io/part-of":    "che.eclipse.org",
						"app.kubernetes.io/managed-by": defaults.GetCheFlavor() + "-operator",
						"app.kubernetes.io/name":       defaults.GetCheFlavor(),
					},
					Annotations: map[string]string{
						"che.eclipse.org/managed-annotations-digest": "0000",
						"annotation-key": "annotation-value",
					},
				},
				TypeMeta: metav1.TypeMeta{
					Kind:       "Ingress",
					APIVersion: networking.SchemeGroupVersion.String(),
				},
				Spec: networking.IngressSpec{
					TLS: []v1.IngressTLS{{Hosts: []string{"test-host"}}},
					Rules: []networking.IngressRule{
						{
							Host: "test-host",
							IngressRuleValue: networking.IngressRuleValue{
								HTTP: &networking.HTTPIngressRuleValue{
									Paths: []networking.HTTPIngressPath{
										{
											Backend: networking.IngressBackend{
												Service: &networking.IngressServiceBackend{
													Name: "che-host",
													Port: networking.ServiceBackendPort{
														Number: 8080,
													},
												},
											},
											Path:     "/",
											PathType: (*networking.PathType)(pointer.StringPtr(string(networking.PathTypeImplementationSpecific))),
										},
									},
								},
							},
						},
					},
				},
			},
		},
	}

	for _, testCase := range testCases {
		t.Run(testCase.name, func(t *testing.T) {
			deployContext := test.GetDeployContext(testCase.cheCluster, []runtime.Object{})

			_, actualIngress := GetIngressSpec(deployContext,
				testCase.ingressName,
				testCase.ingressPath,
				testCase.serviceName,
				testCase.servicePort,
				testCase.ingressComponent,
			)

			assert.Equal(t, testCase.expectedIngress, actualIngress)
		})
	}
}

func TestSyncIngressToCluster(t *testing.T) {
	cheCluster := &chev2.CheCluster{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: "eclipse-che",
			Name:      "eclipse-che",
		},
		Spec: chev2.CheClusterSpec{
			Networking: chev2.CheClusterSpecNetworking{
				Hostname: "host-1",
			},
		},
	}

	deployContext := test.GetDeployContext(cheCluster, []runtime.Object{})
	_, done, err := SyncIngressToCluster(deployContext, "test", "", "service-1", 8080, "component")
	assert.Nil(t, err)
	assert.True(t, done)

	cheCluster.Spec.Networking.Hostname = "host-2"
	_, done, err = SyncIngressToCluster(deployContext, "test", "", "service-2", 8080, "component")
	assert.Nil(t, err)
	assert.True(t, done)

	actual := &networking.Ingress{}
	err = deployContext.ClusterAPI.Client.Get(context.TODO(), types.NamespacedName{Name: "test", Namespace: "eclipse-che"}, actual)
	assert.Nil(t, err)

	assert.Equal(t, "host-2", actual.Spec.Rules[0].Host)
	assert.Equal(t, "service-2", actual.Spec.Rules[0].IngressRuleValue.HTTP.Paths[0].Backend.Service.Name)
}
