package planner

import (
	"context"
	"flag"
	"fmt"
	"os"
	"time"

	_ "github.com/go-sql-driver/mysql"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	host "github.com/pingcap/endless/pkg/workloadnode/tiup"
	"github.com/pingcap/log"
	"github.com/pingcap/test-infra/sdk/resource"
	_ "github.com/pingcap/test-infra/sdk/resource/impl/k8s"

	. "github.com/pingcap/endless/pkg/matcher"
	"github.com/pingcap/endless/pkg/util"
	"github.com/pingcap/endless/pkg/workloadnode"

	"go.uber.org/zap"
)

var _ = util.ParameterizedDescribe("compdeploy", func(flagSet *flag.FlagSet) {
	ctx := suiteTestCtx

	var (
		arch              string
		tidbReplicas      int
		tikvReplicas      int
		tiflashReplicas   int
		version           string
		pdCtl             string
		staging           bool
		ignoreConfigCheck bool
	)
	flagSet.StringVar(&arch, "arch", "amd64", "arch type, by default is amd64, specify arm64 for arm machine")
	flagSet.IntVar(&tidbReplicas, "tidb-replicas", 0, "tidb replicas in the topo")
	flagSet.IntVar(&tikvReplicas, "tikv-replicas", 0, "tikv replicas in the topo")
	flagSet.IntVar(&tiflashReplicas, "tiflash-replicas", 0, "tiflash replicas in the topo")
	flagSet.StringVar(&version, "version", "", "versions to run the workload, e.g. v5.2.2")
	flagSet.StringVar(&pdCtl, "pd-ctl", "", "pd-ctl in json list")
	flagSet.BoolVar(&staging, "staging", false, "use staging mirror for pre-release versions")
	flagSet.BoolVar(&ignoreConfigCheck, "ignore-config-check", false, "to skip the correctness check of the configuration of tidb/tikv/pd, by default, it's false")

	Context("compdeploy", func() {
		os.Setenv("ENDLESS_CMD_STDOUT", "stdout")
		It("prepare", func() {
			// Initialize parameters
			// Initialize variables
			controlNodeName := "tiup" // Node 的 hostname = $name-peer
			controlNode := ctx.Resource(controlNodeName).(resource.WorkloadNode)

			if tidbReplicas == 0 {
				tidbReplicas = 8
			}
			if tikvReplicas == 0 {
				tikvReplicas = 3
			}
			if len(version) == 0 {
				version = "nightly"
			}

			tidbConfig, err := processConfig(`{"new_collations_enabled_on_first_bootstrap": true}`, "tidb")
			if err != nil {
				panic(err)
			}
			if version >= "5.3.0" && version < "6.1.0" {
				// 5.3.0 GA plan-cache
				// >= 6.1.0 use variable and the default is on
				tidbConfig, err = processConfig(`{"new_collations_enabled_on_first_bootstrap": true, "prepared-plan-cache.enabled": true}`, "tidb")
				if err != nil {
					panic(err)
				}
			}

			tikvConfig, _ := processConfig(emptyConfig, "tikv")
			pdConfig := "{}"

			ng_port := ""
			tls := "false"
			benchEnv := fmt.Sprintf(`version: %s, tidbConfig: %s tikvConfig: %s, pdConfig: %s, pdCtl: %s`,
				version, tidbConfig, tikvConfig, pdConfig, pdCtl)
			log.Info(benchEnv)
			ctx2, cancel := context.WithTimeout(ctx, 7*24*time.Hour)
			defer cancel()
			setStr := ""
			if staging {
				setStr = fmt.Sprintf("tiup mirror set %s", stagingMirror)
			} else {
				setStr = fmt.Sprintf("tiup mirror set %s", productionMirror)
			}
			setCmd := workloadnode.CommandContext(ctx2, setStr)
			Try(setCmd.Run(controlNode))
			log.Info("set mirror done")
			topoStr := renderTopo(tidbReplicas, tikvReplicas, tiflashReplicas)
			// enable ng_port when version == ‘nightly" || version >= "v5.3.0"
			if version == "nightly" || version >= "v5.3.0" {
				ng_port = "    ng_port: 12020"
			}

			deployTopo := fmt.Sprintf(tiupTopoTpl, arch, tls, pdConfig, tidbConfig, tikvConfig, topoStr, ng_port)
			log.Info(deployTopo)
			tc := host.NewTiUPCluster(controlNode, controlNodeName+"-peer", deployTopo, clusterName)
			err1 := deployCluster(tc, version, ignoreConfigCheck)
			if err1 != nil {
				log.Error("Deploy BackOff stopped retrying with Error: ", zap.Error(err1))
				Expect(err).Should(BeNil())
			}
			log.Info("Cluster deployed")

			log.Info("Cluster patched")
			Try(tc.Start("--format", "json"))
			log.Info("Cluster started")

			loadBalancer := ctx.Resource("lb").(resource.LoadBalancer)
			dbHost, port := loadBalancer.Endpoint()
			dbPort := fmt.Sprint(port)

			_ = dbHost
			_ = dbPort
		})
	})
})
