package ccb_application_router

import (
	"context"
	"time"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/pingcap/log"
	"github.com/pingcap/test-infra/sdk/core"
	"github.com/pingcap/test-infra/sdk/resource"
	v1 "github.com/prometheus/client_golang/api/prometheus/v1"
	"golang.org/x/sync/errgroup"

	// . "github.com/pingcap/endless/pkg/matcher"
	"github.com/pingcap/endless/pkg/workloadnode/tiup"
)

func RunAPIV2OnlineProcedure(suiteTestCtx core.TestContext, ctx context.Context, tiupCluster *tiup.TiUPCluster, ccbloadClientAPIPrometheus v1.API, instancesCount InstancesCount) {
	pdURL, _ := tiupCluster.ServiceURL(resource.PDAddr)
	pdClientAddr := pdURL.String()
	wn := suiteTestCtx.Resource("workload0").(resource.WorkloadNode)
	g, gctx := errgroup.WithContext(ctx)
	g.Go(func() error {
		return ImporterClientPrepareData(suiteTestCtx, gctx)
	})
	StopCCBLoadClient(wn, 0, instancesCount.WorkloadNodeCount)
	testcaseTimestamp := make([]TestCaseStageInfo, 0)
	By("At stage 1, launching some clients to hit TPS 6.6k")
	By("At stage 1-1, set read-only")
	SetImporterRW(suiteTestCtx, ctx, pdClientAddr, "onlyread")
	log.Info("Testcase runs")
	By("At stage 1-2, start workloads to supply stress(TPS: 6.6k)")
	log.Info("At stage 1-2, start workloads to supply stress(TPS: 6.6k)")
	APIVersion := 1
	LaunchCCBLoadClient(pdClientAddr, wn, 0, 2, APIVersion, 0, 10, ctx)
	stageInfo := StageLast("Stage 1 Empty Cluster-Client-TPS 6.6K", 5*time.Minute)
	testcaseTimestamp = append(testcaseTimestamp, stageInfo)

	By("At stage 2, start workloads to supply stress(TPS: 8.8k)")
	LaunchCCBLoadClient(pdClientAddr, wn, 2, 1, APIVersion, 0, 10, ctx)
	// TODO: adjust the sleep duration before running on prod
	stageInfo = StageLast("Stage 2 Empty Cluster-Client-TPS 8.8k)", 5*time.Minute)
	testcaseTimestamp = append(testcaseTimestamp, stageInfo)

	By("At stage 3, start workloads to supply stress(TPS: 22k)")
	LaunchCCBLoadClient(pdClientAddr, wn, 3, 2, APIVersion, 0, 10, ctx)
	stageInfo = StageLast("Stage 3 Empty Cluster-Client-TPS 22k)", 5*time.Minute)
	testcaseTimestamp = append(testcaseTimestamp, stageInfo)

	// wait tar xvf done, then import the data into the cluster
	Expect(g.Wait()).Should(BeNil())
	By("At stage 4, import data from 2 banks")
	stageInfo = ImportData(suiteTestCtx, ctx, "importer.properties", pdClientAddr, 1, "Stage 4 Import data of 2 banks")
	testcaseTimestamp = append(testcaseTimestamp, stageInfo)
	By("At stage 5, set read-write")
	SetImporterRW(suiteTestCtx, ctx, pdClientAddr, "r-w")
	stageInfo = StageLast("Wait data-with-ttl to expire", 5*time.Minute)
	testcaseTimestamp = append(testcaseTimestamp, stageInfo)

	// TODO: if stop all workload, do upgrade
	By("Upgrade v5.0.4 to v6.1.0")
	stageInfo = UpgradeClusterToV610("Upgrade to V6.1", tiupCluster, "v6.1.0")
	testcaseTimestamp = append(testcaseTimestamp, stageInfo)

	StopCCBLoadClient(wn, 0, instancesCount.WorkloadNodeCount)
	StageLast("Stop all workload clients", 5*time.Minute)

	tiupWorkloadNode := suiteTestCtx.Resource("tiup").(resource.WorkloadNode)
	BackupS3PathV1TTLs := make([]string, 0)
	BackupS3PathV2TTLs := make([]string, 0)
	for i := 0; i < 3; i++ {
		log.S().Infof("Time: %d, Backup", i)
		_, BackupS3PathV1TTL := RawKVBackup("RawKV-Backup V1TTL", tiupWorkloadNode, pdClientAddr, "V1TTL")
		BackupS3PathV1TTLs = append(BackupS3PathV1TTLs, BackupS3PathV1TTL)
		// time.Sleep(1 * time.Minute)
		_, BackupS3PathV2TTL := RawKVBackup("RawKV-Backup V2TTL", tiupWorkloadNode, pdClientAddr, "V2")
		BackupS3PathV2TTLs = append(BackupS3PathV2TTLs, BackupS3PathV2TTL)
		// time.Sleep(1 * time.Minute)
	}
	// TODO: Restore on the same cluster, start r-w ccb workload
	for i, BackPath := range BackupS3PathV1TTLs {
		log.S().Infof("Time: %d, Restore", i)
		RawKVRestore("RawKV-Restore V1TTL", tiupWorkloadNode, pdClientAddr, BackPath)
		time.Sleep(1 * time.Minute)
	}
	SetImporterRW(suiteTestCtx, ctx, pdClientAddr, "r-w")
	// TODO: change the duration of workload and waiting
	LaunchCCBLoadClient(pdClientAddr, wn, 0, instancesCount.WorkloadNodeCount, APIVersion, 15*60, 30, ctx)
	stageInfo = StageLast("Run workload for 15m after restore", 20*time.Minute)
	testcaseTimestamp = append(testcaseTimestamp, stageInfo)

	// TODO: stop all workload
	// TODO: Clean, then restore, start r-w ccb workload
	// CleanCluster("Clean All Data", tiupCluster)
	// tiupCluster.Start()
	// RawKVRestore("RawKV-Restore V1TTL", tiupWorkloadNode, pdClientAddr, BackupS3PathV1TTL)
	// LaunchCCBLoadClient(pdClientAddr, wn, 0, 2, APIVersion, 0, 10, ctx)
	// stageInfo := StageLast("Run workload for 15m after restore", 15*time.Minute)

	StopCCBLoadClient(wn, 0, instancesCount.WorkloadNodeCount)
	// TODO: Destory, and deploy V1TTL, then restore, start r-w ccb workload
	By("Destroy the cluster, and re-deploy one V1TTL Cluster")
	APIVersion = 1
	ReDeployCluster(tiupCluster, instancesCount, APIVersion, "v6.1.0")
	log.S().Info("Destroy cluster, and re-deploy on V1TTL v6.1.0 Cluster ")
	for i, BackPath := range BackupS3PathV1TTLs {
		log.S().Infof("Time: %d, Restore", i)
		RawKVRestore("RawKV-Restore V1TTL after deploy a new cluster", tiupWorkloadNode, pdClientAddr, BackPath)
		time.Sleep(1 * time.Minute)
	}
	log.S().Info("On the re-deployed V1TTL v6.1.0 Cluster, Backup 3 times")
	for i := 0; i < 3; i++ {
		log.S().Infof("Time: %d, Backup", i)
		_, BackupS3PathV1TTL := RawKVBackup("RawKV-Backup V1TTL", tiupWorkloadNode, pdClientAddr, "V1TTL")
		BackupS3PathV1TTLs = append(BackupS3PathV1TTLs, BackupS3PathV1TTL)
		time.Sleep(1 * time.Minute)
		_, BackupS3PathV2TTL := RawKVBackup("RawKV-Backup V2TTL", tiupWorkloadNode, pdClientAddr, "V2")
		BackupS3PathV2TTLs = append(BackupS3PathV2TTLs, BackupS3PathV2TTL)
		time.Sleep(1 * time.Minute)
	}

	// StageLast("Run workload for 15m after restore", 16*time.Minute)
	LaunchCCBLoadClient(pdClientAddr, wn, 0, instancesCount.WorkloadNodeCount, APIVersion, 15*60, 30, ctx)
	stageInfo = StageLast("Run workload for 15m after restore", 20*time.Minute)
	testcaseTimestamp = append(testcaseTimestamp, stageInfo)

	// TODO: Destory, and deploy V2TTL, then restore, start r-w ccb workload
	StopCCBLoadClient(wn, 0, instancesCount.WorkloadNodeCount)
	By("Destroy the cluster and re-deploy one V2TTL Cluster")
	APIVersion = 2
	log.S().Info("Destroy cluster, and re-deploy on V2TTL v6.1.0 Cluster ")
	ReDeployCluster(tiupCluster, instancesCount, APIVersion, "v6.1.0")
	for i, BackPath := range BackupS3PathV2TTLs {
		log.S().Infof("Time: %d, Restore", i)
		RawKVRestore("RawKV-Restore V2TTL after deploy a new cluster", tiupWorkloadNode, pdClientAddr, BackPath)
		time.Sleep(1 * time.Minute)
	}
	LaunchCCBLoadClient(pdClientAddr, wn, 0, instancesCount.WorkloadNodeCount, APIVersion, 15*60, 30, ctx)
	stageInfo = StageLast("Run workload for 15m after restore", 20*time.Minute)
	testcaseTimestamp = append(testcaseTimestamp, stageInfo)
	GenerateReport(ctx, wn, testcaseTimestamp)
	VerifyEachStageMetrics(ctx, ccbloadClientAPIPrometheus, TESTCASE_1_PROMQL, testcaseTimestamp)
}
