package controllers

import (
	"context"
	"fmt"
	"github.com/onsi/gomega"
	"github.com/stretchr/testify/require"
	cloudv1 "github.com/tidbcloud/operationlet/api/v1"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/types"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"
	"testing"
	"time"
)

func TestRestartJob(t *testing.T) {
	testcases := []struct {
		name string
		crds []client.Object
	}{
		{
			name: "test",
			crds: []client.Object{
				&corev1.Pod{
					ObjectMeta: metav1.ObjectMeta{
						Name:              "test1",
						Namespace:         "tidb1",
						CreationTimestamp: metav1.NewTime(time.Unix(1, 0)),
						Labels:            map[string]string{"app.kubernetes.io/instance": "test-pod"},
					},
					Status: corev1.PodStatus{
						Phase: corev1.PodRunning,
					},
				},
			},
		},
	}

	for _, tt := range testcases {
		t.Run(tt.name, func(t *testing.T) {
			job := &cloudv1.OperationCommandJob{
				ObjectMeta: metav1.ObjectMeta{
					Name: "test12",
				},
				Spec: cloudv1.OperationCommandJobSpec{
					JobType:   cloudv1.RestartPod,
					ClusterID: "1",
					TenantID:  "",
					Instance:  "test-pod",
				},
				Status: cloudv1.OperationCommandJobStatus{
					Phase: cloudv1.JobPhasePending,
				},
			}
			g := gomega.NewGomegaWithT(t)
			scheme := runtime.NewScheme()
			g.Expect(corev1.AddToScheme(scheme)).To(gomega.Succeed())
			g.Expect(cloudv1.AddToScheme(scheme)).To(gomega.Succeed())
			cli := fake.NewClientBuilder().WithScheme(scheme).WithObjects(tt.crds...).Build()
			reconciler := &OperationCommandJobReconciler{
				Client: cli,
				Scheme: scheme,
			}
			var target corev1.Pod
			namespacedName := types.NamespacedName{
				Name:      "test1",
				Namespace: "tidb1",
			}
			err := cli.Get(context.TODO(), namespacedName, &target)
			require.Nil(t, err)
			err = reconciler.runCommandJob(context.TODO(), job)
			require.NotNil(t, cli.Get(context.TODO(), namespacedName, &target))
		})
	}
}

func TestCase(t *testing.T) {
	testcases := []struct {
		name string
		crds []client.Object
	}{
		{
			name: "test",
			crds: []client.Object{
				&corev1.Pod{
					ObjectMeta: metav1.ObjectMeta{
						Name:              "test2",
						Namespace:         "tidb1",
						CreationTimestamp: metav1.NewTime(time.Unix(1, 0)),
						Labels:            map[string]string{"app.kubernetes.io/instance": "test-pod-2"},
					},
					Status: corev1.PodStatus{
						Phase: corev1.PodRunning,
					},
				},

				&corev1.Pod{
					ObjectMeta: metav1.ObjectMeta{
						Name:              "test1",
						Namespace:         "tidb1",
						CreationTimestamp: metav1.NewTime(time.Unix(1, 0)),
						Labels:            map[string]string{"app.kubernetes.io/instance": "test-pod-0"},
					},
					Status: corev1.PodStatus{
						Phase: corev1.PodRunning,
					},
				},
			},
		},
	}

	for _, tt := range testcases {
		t.Run(tt.name, func(t *testing.T) {
			g := gomega.NewGomegaWithT(t)
			scheme := runtime.NewScheme()
			g.Expect(corev1.AddToScheme(scheme)).To(gomega.Succeed())
			g.Expect(cloudv1.AddToScheme(scheme)).To(gomega.Succeed())
			cli := fake.NewClientBuilder().WithScheme(scheme).WithObjects(tt.crds...).Build()
			var target corev1.PodList
			label, err := labels.Parse(fmt.Sprintf("app.kubernetes.io/instance=%s", "test-pod-0"))
			require.Nil(t, err)
			err = cli.List(context.TODO(), &target, &client.ListOptions{
				Namespace:     "tidb1",
				LabelSelector: label,
			})
			require.Nil(t, err)
			require.Equal(t, "test1", target.Items[0].Name)
			require.Equal(t, 1, len(target.Items))
		})
	}
}
