package taskdefinition_test

import (
	"context"

	apilifecycle "github.com/keptn/lifecycle-toolkit/lifecycle-operator/apis/lifecycle/v1"
	"github.com/keptn/lifecycle-toolkit/lifecycle-operator/test/component/common"
	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apiserver/pkg/storage/names"
)

//nolint:dupl
var _ = Describe("Taskdefinition", Ordered, func() {
	var (
		taskDefinitionName string
		namespace          string
	)

	BeforeEach(func() { // list var here they will be copied for every spec
		taskDefinitionName = names.SimpleNameGenerator.GenerateName("my-taskdefinition-")
		namespace = "default" // namespaces are not deleted in the api so be careful
	})

	Describe("Creation of a TaskDefinition", func() {
		var (
			taskDefinition *apilifecycle.KeptnTaskDefinition
			configmap      *v1.ConfigMap
		)
		Context("Reconcile TaskDefinition", func() {
			BeforeEach(func() {
			})

			It("create ConfigMap from inline deno", func() {
				By("Create TaskDefinition")
				taskDefinition = &apilifecycle.KeptnTaskDefinition{
					ObjectMeta: metav1.ObjectMeta{
						Name:      taskDefinitionName,
						Namespace: namespace,
					},
					Spec: apilifecycle.KeptnTaskDefinitionSpec{
						Deno: &apilifecycle.RuntimeSpec{
							Inline: apilifecycle.Inline{
								Code: "console.log(Hello);",
							},
						},
					},
				}

				err := k8sClient.Create(context.TODO(), taskDefinition)
				Expect(err).To(BeNil())

				By("Check if ConfigMap was created")

				configmap = &v1.ConfigMap{}
				Eventually(func(g Gomega) {
					err := k8sClient.Get(context.TODO(), types.NamespacedName{
						Namespace: namespace,
						Name:      "keptnfn-" + taskDefinitionName,
					}, configmap)
					g.Expect(err).To(BeNil())
					g.Expect(configmap.Data["code"]).To(Equal(taskDefinition.Spec.Deno.Inline.Code))

				}, "30s").Should(Succeed())

				By("Check if TaskDefinition was updated")

				taskDefinition2 := &apilifecycle.KeptnTaskDefinition{}
				Eventually(func(g Gomega) {
					err := k8sClient.Get(context.TODO(), types.NamespacedName{
						Namespace: namespace,
						Name:      taskDefinition.Name,
					}, taskDefinition2)
					g.Expect(err).To(BeNil())
					g.Expect(taskDefinition2.Status.Function.ConfigMap).To(Equal(configmap.Name))

				}, "30s").Should(Succeed())

				err = k8sClient.Delete(context.TODO(), configmap)
				common.LogErrorIfPresent(err)
			})

			It("TaskDefinition referencing existing Configmap defaulting to Deno", func() {
				By("Create ConfigMap")

				configmap = &v1.ConfigMap{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "my-configmap",
						Namespace: namespace,
					},
					Data: map[string]string{
						"code": "console.log(Hello);",
					},
				}

				err := k8sClient.Create(context.TODO(), configmap)
				Expect(err).To(BeNil())

				By("Create TaskDefinition")
				taskDefinition = &apilifecycle.KeptnTaskDefinition{
					ObjectMeta: metav1.ObjectMeta{
						Name:      taskDefinitionName,
						Namespace: namespace,
					},
					Spec: apilifecycle.KeptnTaskDefinitionSpec{
						Deno: &apilifecycle.RuntimeSpec{
							ConfigMapReference: apilifecycle.ConfigMapReference{
								Name: configmap.Name,
							},
						},
					},
				}

				err = k8sClient.Create(context.TODO(), taskDefinition)
				Expect(err).To(BeNil())

				By("Check if TaskDefinition was updated")

				taskDefinition2 := &apilifecycle.KeptnTaskDefinition{}
				Eventually(func(g Gomega) {
					err := k8sClient.Get(context.TODO(), types.NamespacedName{
						Namespace: namespace,
						Name:      taskDefinition.Name,
					}, taskDefinition2)
					g.Expect(err).To(BeNil())
					g.Expect(taskDefinition2.Status.Function.ConfigMap).To(Equal(configmap.Name))

				}, "30s").Should(Succeed())

				err = k8sClient.Delete(context.TODO(), configmap)
				common.LogErrorIfPresent(err)
			})

			It("TaskDefinition referencing existing Configmap for Python runtime", func() {
				By("Create ConfigMap")

				configmap = &v1.ConfigMap{
					ObjectMeta: metav1.ObjectMeta{
						Name:      "my-configmap",
						Namespace: namespace,
					},
					Data: map[string]string{
						"code": "print(\"Hello, World!\")",
					},
				}

				err := k8sClient.Create(context.TODO(), configmap)
				Expect(err).To(BeNil())

				By("Create TaskDefinition")
				taskDefinition = &apilifecycle.KeptnTaskDefinition{
					ObjectMeta: metav1.ObjectMeta{
						Name:      taskDefinitionName,
						Namespace: namespace,
					},
					Spec: apilifecycle.KeptnTaskDefinitionSpec{
						Python: &apilifecycle.RuntimeSpec{
							ConfigMapReference: apilifecycle.ConfigMapReference{
								Name: configmap.Name,
							},
						},
					},
				}

				err = k8sClient.Create(context.TODO(), taskDefinition)
				Expect(err).To(BeNil())

				By("Check if TaskDefinition was updated")

				taskDefinition2 := &apilifecycle.KeptnTaskDefinition{}
				Eventually(func(g Gomega) {
					err := k8sClient.Get(context.TODO(), types.NamespacedName{
						Namespace: namespace,
						Name:      taskDefinition.Name,
					}, taskDefinition2)
					g.Expect(err).To(BeNil())
					g.Expect(taskDefinition2.Status.Function.ConfigMap).To(Equal(configmap.Name))

				}, "30s").Should(Succeed())

				err = k8sClient.Delete(context.TODO(), configmap)
				common.LogErrorIfPresent(err)
			})

			It("TaskDefinition referencing non-existing Configmap", func() {
				By("Create TaskDefinition")
				taskDefinition = &apilifecycle.KeptnTaskDefinition{
					ObjectMeta: metav1.ObjectMeta{
						Name:      taskDefinitionName,
						Namespace: namespace,
					},
					Spec: apilifecycle.KeptnTaskDefinitionSpec{
						Deno: &apilifecycle.RuntimeSpec{
							ConfigMapReference: apilifecycle.ConfigMapReference{
								Name: "my-configmap-non-existing",
							},
						},
					},
				}

				err := k8sClient.Create(context.TODO(), taskDefinition)
				Expect(err).To(BeNil())

				By("Check that ConfigMap does not exists")

				configmap = &v1.ConfigMap{}
				Eventually(func(g Gomega) {
					err := k8sClient.Get(context.TODO(), types.NamespacedName{
						Namespace: namespace,
						Name:      "my-configmap-non-existing",
					}, configmap)
					g.Expect(err).NotTo(BeNil())
				}, "30s").Should(Succeed())

				By("Check that TaskDefinition Status was not updated")

				taskDefinition2 := &apilifecycle.KeptnTaskDefinition{}
				Eventually(func(g Gomega) {
					err := k8sClient.Get(context.TODO(), types.NamespacedName{
						Namespace: namespace,
						Name:      taskDefinition.Name,
					}, taskDefinition2)
					g.Expect(err).To(BeNil())
					g.Expect(taskDefinition2.Status.Function.ConfigMap).NotTo(Equal("my-configmap-non-existing"))

				}, "30s").Should(Succeed())

			})

			AfterEach(func() {
				err := k8sClient.Delete(context.TODO(), taskDefinition)
				common.LogErrorIfPresent(err)

			})
		})
	})
})
