package common

import (
	"context"
	"testing"

	opv1alpha1 "github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1"
	"github.com/stretchr/testify/require"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"

	"github.com/tidbcloud/infra-provider/pkg/consts"
)

var enableSEMData = `
[security]
  a = "b"
  enable-sem = true
`

var disableSEMData = `
[security]
  a = "b"
  enable-sem = false
`

var emptySEMData = `
[security]
  a = "b"
`

var semScheme *runtime.Scheme

func init() {
	semScheme = runtime.NewScheme()
	_ = corev1.AddToScheme(semScheme)
	_ = opv1alpha1.AddToScheme(semScheme)
}

func TestIsSEMSetted(t *testing.T) {
	setted, err := isSEMSetted(enableSEMData)
	require.Nil(t, err)
	require.True(t, setted)

	setted, err = isSEMSetted(disableSEMData)
	require.Nil(t, err)
	require.False(t, setted)

	setted, err = isSEMSetted(emptySEMData)
	require.Nil(t, err)
	require.False(t, setted)
}

func TestAnyPodEnableSEM(t *testing.T) {
	cli := fake.NewClientBuilder().WithScheme(semScheme).Build()
	ctx := context.Background()

	tc := &opv1alpha1.TidbCluster{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: "ns",
			Name:      "db",
		},
	}
	err := cli.Create(ctx, tc)
	require.Nil(t, err)

	enableCM := &corev1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: tc.Namespace,
			Name:      "enable",
		},
		Data: map[string]string{
			"config-file": enableSEMData,
		},
	}
	err = cli.Create(ctx, enableCM)
	require.Nil(t, err)

	disableCM := &corev1.ConfigMap{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: tc.Namespace,
			Name:      "disable",
		},
		Data: map[string]string{
			"config-file": disableSEMData,
		},
	}
	err = cli.Create(ctx, disableCM)
	require.Nil(t, err)

	pod0 := buildPod(tc.Namespace, tc.Name, "pod0", disableCM.Name)
	err = cli.Create(ctx, pod0)
	require.Nil(t, err)
	pod1 := buildPod(tc.Namespace, tc.Name, "pod1", disableCM.Name)
	err = cli.Create(ctx, pod1)
	require.Nil(t, err)
	otherNSPod := buildPod(tc.Namespace+"-other", tc.Name, "pod101", enableCM.Name)
	err = cli.Create(ctx, otherNSPod)
	require.Nil(t, err)
	enable, err := anyPodEnableSEM(ctx, cli, tc)
	require.Nil(t, err)
	require.False(t, enable)

	pod2 := buildPod(tc.Namespace, tc.Name, "pod2", enableCM.Name)
	err = cli.Create(ctx, pod2)
	require.Nil(t, err)
	enable, err = anyPodEnableSEM(ctx, cli, tc)
	require.Nil(t, err)
	require.True(t, enable)
}

func buildPod(tcNS string, tcName string, name string, cmName string) *corev1.Pod {
	pod := &corev1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Namespace: tcNS,
			Name:      name,
			Labels: map[string]string{
				consts.InstanceLabelKey:  tcName,
				consts.ComponentLabelKey: "tidb",
			},
		},
		Spec: corev1.PodSpec{
			Volumes: []corev1.Volume{
				{
					Name: "config",
					VolumeSource: corev1.VolumeSource{
						ConfigMap: &corev1.ConfigMapVolumeSource{
							LocalObjectReference: corev1.LocalObjectReference{
								Name: cmName,
							},
						},
					},
				},
			},
		},
	}

	return pod
}
