package functionality

import (
	"time"

	"github.com/onsi/ginkgo"
	"github.com/onsi/gomega"
	"github.com/pingcap/endless/pkg/matcher"
	"github.com/pingcap/endless/pkg/workload"
	"github.com/pingcap/endless/testcase/geopartition/utils"
)

func constraintsSyntaxTest(ctx *utils.SuiteContext) {
	ginkgo.It("Constraints Syntax (List syntax) #constraints_syntax_1#", func() {
		defer func() {
			workload.MustExec(ctx.DB, "DROP TABLE IF EXISTS t1,t2,t3,tx")
			workload.MustExec(ctx.DB, "DROP PLACEMENT POLICY IF EXISTS ssd")
		}()
		workload.MustExec(ctx.DB, "DROP TABLE IF EXISTS t1,t2,t3,tx")
		workload.MustExec(ctx.DB, "DROP PLACEMENT POLICY IF EXISTS ssd")

		workload.MustExec(ctx.DB, "CREATE PLACEMENT POLICY ssd CONSTRAINTS=\"[+disk=ssd]\";")
		workload.MustExec(ctx.DB, "CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY auto_increment, b VARBINARY(65535)) PLACEMENT POLICY=ssd;")
		for n := 0; n < 100; n++ {
			workload.MustExec(ctx.DB, "insert into t1 (b) values (?)", string(n))
		}
		matcher.Try(utils.WaitScheduled(ctx.DB, "t1", time.Minute))
		data := utils.ReadAll(utils.MustQuery(ctx.DB, "SHOW PLACEMENT WHERE target='POLICY ssd'"))
		gomega.Expect(data[0][0]).To(gomega.Equal("POLICY ssd"))
		gomega.Expect(data[0][1]).To(gomega.Equal("CONSTRAINTS=\"[+disk=ssd]\""))

		workload.MustExec(ctx.DB, "ALTER TABLE t1 PLACEMENT POLICY=default;")
		workload.MustExec(ctx.DB, "ALTER TABLE t1 PLACEMENT POLICY=ssd;")
		matcher.Try(utils.WaitScheduled(ctx.DB, "t1", time.Minute))
		utils.CheckRegions(ctx, "t1", "", func(r utils.Regions) {
			r.CheckLeaderPlacement("+disk=ssd").
				CheckFollowerPlacement("+disk=ssd", 2).
				CheckNoPeersLeft()
		})

		workload.MustExec(ctx.DB, "ALTER PLACEMENT POLICY ssd FOLLOWER_CONSTRAINTS=\"[+disk=ssd]\" FOLLOWERS=2;")
		matcher.Try(utils.WaitScheduled(ctx.DB, "t1", time.Minute))
		utils.CheckRegions(ctx, "t1", "", func(r utils.Regions) {
			r.CheckLeaderPlacement("").
				CheckFollowerPlacement("+disk=ssd", 2).
				CheckNoPeersLeft()
		})

		workload.MustExec(ctx.DB, "ALTER PLACEMENT POLICY ssd LEADER_CONSTRAINTS=\"[+disk=ssd]\";")
		matcher.Try(utils.WaitScheduled(ctx.DB, "t1", time.Minute))
		utils.CheckRegions(ctx, "t1", "", func(r utils.Regions) {
			r.CheckLeaderPlacement("+disk=ssd").
				CheckFollowerPlacement("", 2).
				CheckNoPeersLeft()
		})

		workload.MustExec(ctx.DB, "ALTER PLACEMENT POLICY ssd LEADER_CONSTRAINTS='[+region=us-east-1,+disk=ssd]' LEARNER_CONSTRAINTS='[+region=us-west-1]' LEARNERS=2;")
		matcher.Try(utils.WaitScheduled(ctx.DB, "t1", time.Minute))
		utils.CheckRegions(ctx, "t1", "", func(r utils.Regions) {
			r.CheckLeaderPlacement("+region=us-east-1,+disk=ssd").
				CheckFollowerPlacement("", 2).
				CheckLearnerPlacement("+region=us-west-1", 2).
				CheckNoPeersLeft()
		})

		workload.MustExec(ctx.DB, "ALTER PLACEMENT POLICY ssd LEADER_CONSTRAINTS=\"[+disk=ssd]\" CONSTRAINTS=\"[+disk=ssd]\"  LEADER_CONSTRAINTS=\"[+region=us-west-1]\";")
		matcher.Try(utils.WaitScheduled(ctx.DB, "t1", time.Minute))
		utils.CheckRegions(ctx, "t1", "", func(r utils.Regions) {
			r.CheckLeaderPlacement("+disk=ssd,+region=us-west-1").
				CheckFollowerPlacement("+disk=ssd", 2).
				CheckNoPeersLeft()
		})

		workload.MustExec(ctx.DB, "ALTER PLACEMENT POLICY ssd LEADER_CONSTRAINTS=\"[+region=us-east-1]\" CONSTRAINTS=\"[+disk=ssd]\" LEARNER_CONSTRAINTS=\"[+region=us-east-2]\" LEARNERS=1 FOLLOWERS=1;")
		matcher.Try(utils.WaitScheduled(ctx.DB, "t1", time.Minute))
		utils.CheckRegions(ctx, "t1", "", func(r utils.Regions) {
			r.CheckLeaderPlacement("+region=us-east-1,+disk=ssd").
				CheckFollowerPlacement("", 1).
				CheckLearnerPlacement("+region=us-east-2", 1).
				CheckNoPeersLeft()
		})

		workload.MustExec(ctx.DB, "ALTER PLACEMENT POLICY ssd LEADER_CONSTRAINTS=\"[+disk=ssd]\" CONSTRAINTS=\"[+disk=ssd]\"  FOLLOWER_CONSTRAINTS=\"[+region=us-west-1]\";")
		data = utils.ReadAll(utils.MustQuery(ctx.DB, "SHOW PLACEMENT FOR TABLE t1"))
		gomega.Expect(data[0][2]).To(gomega.Equal("PENDING"))
	})

	ginkgo.It("Constraints Syntax (Dictionary syntax) #constraints_syntax_2#", func() {
		defer func() {
			workload.MustExec(ctx.DB, "DROP TABLE IF EXISTS t1,t2,t3,tx")
			workload.MustExec(ctx.DB, "DROP PLACEMENT POLICY IF EXISTS ssd")
		}()
		workload.MustExec(ctx.DB, "DROP TABLE IF EXISTS t1,t2,t3,tx")
		workload.MustExec(ctx.DB, "DROP PLACEMENT POLICY IF EXISTS ssd")

		workload.MustExec(ctx.DB, "CREATE PLACEMENT POLICY ssd CONSTRAINTS=\"[+disk=ssd]\";")
		workload.MustExec(ctx.DB, "CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY auto_increment, b VARBINARY(65535)) PLACEMENT POLICY=ssd;")
		for n := 0; n < 100; n++ {
			workload.MustExec(ctx.DB, "insert into t1 (b) values (?)", string(n))
		}

		workload.MustExec(ctx.DB, "ALTER TABLE t1 PLACEMENT POLICY=default;")
		workload.MustExec(ctx.DB, "ALTER TABLE t1 PLACEMENT POLICY=ssd;")
		matcher.Try(utils.WaitScheduled(ctx.DB, "t1", time.Minute))
		utils.CheckRegions(ctx, "t1", "", func(r utils.Regions) {
			r.CheckLeaderPlacement("+disk=ssd").
				CheckFollowerPlacement("+disk=ssd", 2).
				CheckNoPeersLeft()
		})

		workload.MustExec(ctx.DB, "ALTER PLACEMENT POLICY ssd FOLLOWER_CONSTRAINTS=\"{+disk=ssd: 1}\";")
		matcher.Try(utils.WaitScheduled(ctx.DB, "t1", time.Minute))
		utils.CheckRegions(ctx, "t1", "", func(r utils.Regions) {
			r.CheckLeaderPlacement("").
				CheckFollowerPlacement("+disk=ssd", 1).
				CheckNoPeersLeft()
		})

		workload.MustExec(ctx.DB, "ALTER PLACEMENT POLICY ssd LEARNER_CONSTRAINTS=\"{+disk=ssd: 3}\";")
		matcher.Try(utils.WaitScheduled(ctx.DB, "t1", time.Minute))
		utils.CheckRegions(ctx, "t1", "", func(r utils.Regions) {
			r.CheckLeaderPlacement("").
				CheckFollowerPlacement("", 2).
				CheckLearnerPlacement("+disk=ssd", 3).
				CheckNoPeersLeft()
		})

		workload.MustExec(ctx.DB, "ALTER PLACEMENT POLICY ssd CONSTRAINTS=\"[+disk=ssd]\";")
		matcher.Try(utils.WaitScheduled(ctx.DB, "t1", time.Minute))
		utils.CheckRegions(ctx, "t1", "", func(r utils.Regions) {
			r.CheckLeaderPlacement("+disk=ssd").
				CheckFollowerPlacement("+disk=ssd", 2).
				CheckNoPeersLeft()
		})

		utils.MustExecError(ctx.DB, 8243, "ALTER PLACEMENT POLICY ssd FOLLOWER_CONSTRAINTS=\"{+disk=ssd: 1}\" CONSTRAINTS=\"[+region=’us-west-1’]\";")
	})
}
