package tidbcluster

import (
	"context"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	pkgErrors "github.com/pkg/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	"github.com/pingcap/test-infra/sdk/resource/impl/k8s"

	apiresource "github.com/pingcap/test-infra/common/model/resource"
	"github.com/pingcap/test-infra/sdk/e2etest/framework"
	"github.com/pingcap/test-infra/sdk/resource"
)

var _ = Describe("DMCluster Test", func() {
	Context("DMCluster.Create", func() {
		f := framework.NewDefaultFramework("testbed-dmcluster-create")

		It("DMCluster's testbed should equal to testbed's name", func() {
			dmCluster := f.CreateDMCluster(f.CreateTestbed())
			Expect(dmCluster.Testbed).Should(Equal(f.Testbed()))
			Expect(dmCluster.Type).Should(Equal(apiresource.ResourceTypeDMCluster))
		})

		It("DMCluster should be ready after a while", func() {
			dmCluster := f.CreateDMCluster(f.CreateTestbed())

			f.WaitForDMClusterReady(dmCluster, framework.TestContext.ResourceWaitReadyTimeout)
		})
	})

	Context("DMCluster.Get", func() {
		f := framework.NewDefaultFramework("testbed-dmcluster-get")

		It("DMCluster's testbed should equal to testbed's name", func() {
			dmCluster := f.CreateDMCluster(f.CreateTestbed())
			dmCluster = f.GetDMCluster(dmCluster.Handle())

			Expect(dmCluster.Testbed).Should(Equal(f.Testbed()))
			Expect(dmCluster.Type).Should(Equal(apiresource.ResourceTypeDMCluster))
		})

		It("DMCluster should be ready after a while", func() {
			dmCluster := f.CreateDMCluster(f.CreateTestbed())
			dmCluster = f.GetDMCluster(dmCluster.Handle())

			f.WaitForDMClusterReady(dmCluster, framework.TestContext.ResourceWaitReadyTimeout)
		})
	})

	Context("DMCluster.Delete", func() {
		f := framework.NewDefaultFramework("testbed-dmcluster-delete")

		It("DMCluster's delete should clean all resources", func() {
			dmCluster := f.CreateDMCluster(f.CreateTestbed())

			f.WaitForDMClusterReady(dmCluster, framework.TestContext.ResourceWaitReadyTimeout)

			f.DeleteDMWaited(dmCluster)

			pods := f.AllPods()
			Expect(len(pods.Items)).Should(Equal(0))
			Expect(len(f.AllPVCs().Items)).Should(Equal(0))
			Expect(len(f.AllServices().Items)).Should(Equal(0))
			Expect(len(f.AllConfigmaps().Items)).Should(Equal(1))
		})
	})

	Context("DMCluster.Exec", func() {
		f := framework.NewDefaultFramework("testbed-dmcluster-exec")

		It("DMCluster's list-member should work well", func() {
			dmCluster := f.CreateDMCluster(f.CreateTestbed())
			f.WaitForDMClusterReady(dmCluster, framework.TestContext.ResourceWaitReadyTimeout)

			stdout, _, _, _ := dmCluster.Exec("dc-dm-master-0", resource.DMMasterContainerName, "/dmctl", "--master-addr=127.0.0.1:8261", "list-member")
			Expect(stdout).Should(ContainSubstring("\"result\": true"))
		})
	})

	Context("DMCluster.Upgrade cluster", func() {
		f := framework.NewDefaultFramework("testbed-dmcluster-upgrade")

		It("DMCluster upgrade cluster should work", func() {
			dmCluster := f.CreateDMCluster(f.CreateTestbed())
			f.WaitForDMClusterReady(dmCluster, framework.TestContext.ResourceWaitReadyTimeout)

			err := dmCluster.Upgrade(resource.DMClusterUpgradeOptions{
				Version: "v5.4.0",
				Timeout: 10 * time.Minute,
			})
			framework.ExpectNoError(err)
			framework.ExpectNoError(dmCluster.Sync())

			Expect(dmCluster.Status.Master.Image).Should(Equal("hub.pingcap.net/qa/dm:v5.4.0"))
			Expect(dmCluster.Status.Worker.Image).Should(Equal("hub.pingcap.net/qa/dm:v5.4.0"))

			sts, err := f.KubeClientSetPack.ClientSet.AppsV1().StatefulSets(dmCluster.Namespace()).Get(context.TODO(), "dc-dm-master", metav1.GetOptions{})
			framework.ExpectNoError(err)
			Expect(sts.Spec.Template.Spec.Containers[0].Image, "hub.pingcap.net/qa/dm:v5.4.0")

			sts, err = f.KubeClientSetPack.ClientSet.AppsV1().StatefulSets(dmCluster.Namespace()).Get(context.TODO(), "dc-dm-worker", metav1.GetOptions{})
			framework.ExpectNoError(err)
			Expect(sts.Spec.Template.Spec.Containers[0].Image, "hub.pingcap.net/qa/dm:v5.4.0")
		})

		It("DMCluster upgrade cluster timeout should work", func() {
			dmCluster := f.CreateDMCluster(f.CreateTestbed())
			f.WaitForDMClusterReady(dmCluster, framework.TestContext.ResourceWaitReadyTimeout)

			err := dmCluster.Upgrade(resource.DMClusterUpgradeOptions{
				Version: "v5.4.0",
				Timeout: 1 * time.Second,
			})
			Expect(pkgErrors.Cause(err)).Should(Equal(k8s.ErrUpgradeTimeout))
		})
	})

	Context("DMCluster.Archive", func() {
		f := framework.NewDefaultFramework("testbed-dmcluster-archive")

		It("DMCluster.Archive should work well", func() {
			dmCluster := f.CreateDMCluster(f.CreateTestbed())
			f.WaitForDMClusterReady(dmCluster, framework.TestContext.ResourceWaitReadyTimeout)

			var data []string

			f.ArchiveDMCluster(dmCluster.Handle(), f.Archiver(&data))
			Expect(len(data)).Should(Equal(2))
			Expect(data[0]).Should(ContainSubstring("Welcome to dm-"))
			Expect(data[1]).Should(ContainSubstring("Welcome to dm-"))
		})
	})
})
