package sdk

import (
	"testing"

	. "github.com/onsi/gomega"
	"github.com/pingcap/errors"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/utils/pointer"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/golang/mock/gomock"
	cloudv1 "github.com/tidbcloud/infra-api/api/v1"
	"github.com/tidbcloud/infra-provider/pkg/gitops-sdk/revision/mock_revision"
)

func TestGetClusterRevision(t *testing.T) {
	labels := map[string]string{
		cloudv1.ProjectLabel:  "456",
		cloudv1.TenantTagKey:  "123",
		cloudv1.ClusterTagKey: "789",
		cloudv1.VersionLabel:  "v6.5.1",
	}
	cc := &cloudv1.ClusterConfig{
		ObjectMeta: metav1.ObjectMeta{Labels: labels},
		Spec: cloudv1.ClusterConfigSpec{
			PD: &cloudv1.Configuration{
				BaseImage: pointer.String("image"),
			},
			ConfigMeta: &cloudv1.ConfigMeta{
				GitCommitID:   "abcdefghijk",
				ConfigVersion: 0,
			},
		}}
	cr := &cloudv1.ConfigRevision{
		ObjectMeta: metav1.ObjectMeta{
			Labels: labels, Name: "basev6.5.1-t123-c789-abcdefg-3fcae7e0"},
		Spec: cloudv1.ConfigRevisionSpec{
			PD: &cloudv1.Configuration{
				BaseImage: pointer.String("image"),
			},
		},
	}
	crKey := client.ObjectKey{Name: cr.Name}
	existCR := cr.DeepCopy()

	t.Run("no exist cr", func(t *testing.T) {
		ctrl := gomock.NewController(t)
		defer ctrl.Finish()
		g := NewGomegaWithT(t)

		revisioner := mock_revision.NewMockInterface(ctrl)
		revisioner.EXPECT().GetConfigRevisions(crKey).Return(nil, errors.Annotate(apierrors.NewNotFound(schema.GroupResource{}, cr.Name), ""))
		revisioner.EXPECT().CreateConfigRevision(gomock.Any()).Return(cr, nil)

		r1, err := GetClusterRevision(revisioner, cc, true)
		g.Expect(err).To(Succeed())
		g.Expect(r1).To(Equal(cr))
	})
	t.Run("no exist cr and create is false", func(t *testing.T) {
		ctrl := gomock.NewController(t)
		defer ctrl.Finish()
		g := NewGomegaWithT(t)

		revisioner := mock_revision.NewMockInterface(ctrl)
		revisioner.EXPECT().GetConfigRevisions(crKey).Return(nil, apierrors.NewNotFound(schema.GroupResource{}, cr.Name))

		r1, err := GetClusterRevision(revisioner, cc, false)
		g.Expect(err).To(Succeed())
		g.Expect(r1.Name == cr.Name).To(BeTrue())
	})
	t.Run("cr is already existing, and have the same conf", func(t *testing.T) {
		ctrl := gomock.NewController(t)
		defer ctrl.Finish()
		g := NewGomegaWithT(t)

		revisioner := mock_revision.NewMockInterface(ctrl)
		revisioner.EXPECT().GetConfigRevisions(crKey).Return(existCR, nil)

		r1, err := GetClusterRevision(revisioner, cc, true)
		g.Expect(err).To(Succeed())
		g.Expect(r1).To(Equal(existCR))
	})

	t.Run("cr is already existing, but have conf diff", func(t *testing.T) {
		ctrl := gomock.NewController(t)
		defer ctrl.Finish()
		g := NewGomegaWithT(t)
		existCR.Spec.PD.BaseImage = pointer.String("another image")

		revisioner := mock_revision.NewMockInterface(ctrl)
		revisioner.EXPECT().GetConfigRevisions(crKey).Return(existCR, nil)

		_, err := GetClusterRevision(revisioner, cc, true)
		g.Expect(err).Should(HaveOccurred())
	})
}
