package scenario

import (
	"context"
	"database/sql"
	"encoding/json"
	"flag"

	. "github.com/onsi/ginkgo"
	"github.com/pingcap/log"
	"github.com/pingcap/test-infra/sdk/resource"
	"go.uber.org/zap"

	//"github.com/pingcap/endless/pkg/client/pd"
	"github.com/pingcap/endless/pkg/client/tidb"
	. "github.com/pingcap/endless/pkg/matcher"
	. "github.com/pingcap/endless/pkg/util"
)

var _ = ParameterizedDescribe("scenario", func(flagSet *flag.FlagSet) {
	var (
		// Workload related vars.
		configStr string
		config    Config

		// Resources related vars.
		tc resource.TiDBCluster

		// Test case control parameters.
		// When runTime is reached, the ctx becomes timeout.
		rootCtx    context.Context
		rootCancel context.CancelFunc
	)

	// Workload flags.
	flagSet.StringVar(&configStr, "configstr", "{}", "")

	BeforeEach(func() {
		// Default value for config.
		config = DefaultConfig()

		// Initialize config.
		log.Info("Run with config", zap.String("config", configStr))
		Try(json.Unmarshal([]byte(configStr), &config))

		// Initialize root context.
		rootCtx, rootCancel = context.WithCancel(suiteTestCtx)

		// Initialize resources.
		tc = suiteTestCtx.Resource("tc").(resource.TiDBCluster)
	})

	AfterEach(func() {
		rootCancel()
	})

	// To keep the code structure clean and easy to understand. Add a context nil for
	// those test cases with no context.
	Context("nil", func() {
		TestCase("load workload data", "oltp_scenario_workloadload_001", func() {
			TWorkloadLoad001(rootCtx, config, tc)
		})
	})

	// Please ensure workload is running before running the following test cases.
	// You can run test case `scenario_workload_running` to run the workload.
	Context("workload is running", func() {
		var (
			db         *sql.DB
			tidbClient *tidb.Client
			//pdClient   *pd.Client
		)

		BeforeEach(func() {
			// db is closed in AfterEach.
			db = Try(tc.GetDB("")).(*sql.DB)
			tidbClient = tidb.NewClient(db)
			//pdClient = Try(pd.NewPDClient(tc)).(*pd.Client)

			WorkloadRunForever(rootCtx, config, tc)
			PreCheck(rootCtx, tc)
		})

		AfterEach(func() {
			defer db.Close()

			if !CurrentGinkgoTestDescription().Failed {
				PostCheck(rootCtx, tc)
			}
		})

		TestCase("qps/latency should be stable", "oltp_scenario_workloadrun_001", func() {
			TWorkloadRun001(rootCtx, config)
		})

		// Scale related test cases.
		Describe("scale", func() {
			TestCase("scale out cluster", "oltp_scenario_scale_001", func() {
				TScale001(rootCtx, config, tc, tidbClient)
			})
			TestCase("scale in cluster", "oltp_scenario_scale_002", func() {
				TScale002(rootCtx, config, tc, tidbClient)
			})
		})

		TestCase("", "oltp_scenario_fullscan_001", func() {
			TFullScan001(rootCtx, config, tc, tidbClient)
		})

		TestCase("", "oltp_scenario_addindex_001", func() {
			TAddIndex001(rootCtx, config, tc, tidbClient)
		})

		TestCase("", "oltp_scenario_addcolumn_001", func() {
			TAddColumn001(rootCtx, config, tc, tidbClient)
		})

		TestCase("", "oltp_scenario_truncate_001", func() {
			TTruncate001(rootCtx, config, tc, tidbClient)
		})

		TestCase("", "oltp_scenario_analyze_001", func() {
			TAnalyze001(rootCtx, config, tc, tidbClient)
		})
	})
})
