// Copyright 2021 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package performance

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"
	"github.com/pingcap/test-infra/sdk/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func regionalTest(ctx *SuiteContext) {
	It("Performance regional test", func() {
		defer func() {
			MustExec(ctx.DB, "DROP TABLE IF EXISTS t1")
			MustExec(ctx.DB, "DROP PLACEMENT POLICY IF EXISTS p1")
			MustExec(ctx.DB, "DROP PLACEMENT POLICY IF EXISTS p2")
		}()
		MustExec(ctx.DB, "set tidb_enable_list_partition=1")
		MustExec(ctx.DB, "DROP TABLE IF EXISTS t1")
		MustExec(ctx.DB, "DROP PLACEMENT POLICY IF EXISTS p1")
		MustExec(ctx.DB, "DROP PLACEMENT POLICY IF EXISTS p2")
		MustExec(ctx.DB, "CREATE PLACEMENT POLICY p1 PRIMARY_REGION='us-east-1' REGIONS='us-east-1,us-east-2' SCHEDULE='majority_in_primary'")
		MustExec(ctx.DB, "CREATE PLACEMENT POLICY p2 PRIMARY_REGION='us-east-2' REGIONS='us-east-1,us-east-2' SCHEDULE='majority_in_primary'")

		tc := ctx.TC
		chaosClient := tc.ChaosClient()
		selector := Try(tc.ChaosSelect(resource.TiDBClusterSelectorOpts{
			TiDBClusterTiKVSelectorSpec: &resource.TiDBClusterTiKVSelectorSpec{
				StoreLabelSelector: &metav1.LabelSelector{
					MatchLabels: map[string]string{"region": "us-east-2"},
				},
			},
		})).([]resource.ChaosSelector)

		chaosId := Try(chaosClient.Create(resource.InjectChaosOptions{
			Selector: selector,
			ExperimentSpec: &resource.NetworkLatencySpec{
				Latency: "100ms",
			},
		})).(resource.ChaosIdentifier)
		defer func() {
			Try(tc.ChaosClient().Delete(chaosId))
		}()

		MustExec(ctx.DB, "CREATE TABLE t1 (region VARCHAR(32), name VARCHAR(32)) PARTITION BY LIST COLUMNS(region) "+
			"(PARTITION p0 VALUES IN('r1') PLACEMENT POLICY p1,"+
			"PARTITION p1 VALUES IN('r2') PLACEMENT POLICY p2"+
			")")

		time.Sleep(time.Second * 5)
		// Prefetch auto id cache before test
		MustExec(ctx.DB, "INSERT INTO t1 values('r1', 'name0')")

		// Latency write p0 should less than 100ms
		durationStr := ReadAll(MustQuery(ctx.DB, "TRACE INSERT INTO t1 values ('r1', 'name1')"))[0][2]
		du := Try(time.ParseDuration(durationStr)).(time.Duration)
		Expect(du).Should(Satisfy(func(d time.Duration) bool { return d < time.Millisecond*100 }))

		// Latency read p0 should less than 100ms
		durationStr = ReadAll(MustQuery(ctx.DB, "TRACE SELECT * FROM t1 where region='r1' and name='name1'"))[0][2]
		du = Try(time.ParseDuration(durationStr)).(time.Duration)
		Expect(du).Should(Satisfy(func(d time.Duration) bool { return d < time.Millisecond*100 }))

		// Latency write p1 should more than 200ms
		durationStr = ReadAll(MustQuery(ctx.DB, "TRACE INSERT INTO t1 values ('r2', 'name2')"))[0][2]
		du = Try(time.ParseDuration(durationStr)).(time.Duration)
		Expect(du).Should(Satisfy(func(d time.Duration) bool { return d > time.Millisecond*200 }))

		// Latency read p1 should more than 100ms and less than 200ms
		durationStr = ReadAll(MustQuery(ctx.DB, "TRACE SELECT * FROM t1 where region='r2' and name='name2'"))[0][2]
		du = Try(time.ParseDuration(durationStr)).(time.Duration)
		Expect(du).Should(Satisfy(func(d time.Duration) bool { return d > time.Millisecond*100 && d < time.Millisecond*200 }))

	})
}
