package workload

import (
	"context"

	//"io"
	"math"
	"strings"
	"time"

	. "github.com/onsi/gomega"
	. "github.com/pingcap/endless/pkg/util"
	"github.com/pingcap/endless/testcase/oltp/oltppkg"
	"github.com/pingcap/log"
	"github.com/pingcap/test-infra/sdk/resource"
	"go.uber.org/zap"
	"golang.org/x/sync/errgroup"
)

func OLTP_WORKLOAD_FUN_001(
	ctx context.Context,
	//tc resource.TiDBCluster,
	tc resource.MySQLCompatible,
	benchToolset resource.WorkloadNode,
	caseCmdParms oltppkg.CaseCmdParms,
	workloadRunPara oltppkg.WorkloadRunParms,
) {
	_, initSumSize, err := oltppkg.GetStoreSizeByType(tc, "used_size")
	Expect(err).Should(Succeed())

	workloadType := caseCmdParms.WorkloadType.Type[0]
	var runTime time.Duration
	if caseCmdParms.RunTime.TotalRunTime != 0 {
		runTime = caseCmdParms.RunTime.TotalRunTime
	} else {
		runTime = 1 * time.Hour
	}
	log.Info("Test will run ", zap.Duration("case runTime", runTime))
	ctxAll, cancel := context.WithTimeout(ctx, runTime)
	defer cancel()
	g, ctxg := errgroup.WithContext(ctxAll)

	log.Info("start run workload")
	if caseCmdParms.SkipRunWorkload {
		workloadRunPara.InitAndStart(ctx, tc, benchToolset, caseCmdParms, false)
	}

	if caseCmdParms.WorkloadType.Type[0] == "sysbench_bulk_insert" {
		workloadCheckParms := oltppkg.WorkloadCheckParameters{
			IsCheck:   true,
			IgnoreErr: strings.Split(caseCmdParms.SysbenchParms.WorkloadCheckIgnoreErrors, ","),
		}
		log.Info("Will ingore workload errors", zap.Strings("workloadIgnoreErros", workloadCheckParms.IgnoreErr))
		oltppkg.FunCommonCheck(ctxg, tc, g, runTime, workloadRunPara.Cmdpr, workloadCheckParms)
	} else {
		oltppkg.FunCommonCheck(ctxg, tc, g, runTime, workloadRunPara.Cmdpr)
	}

	g.Go(WithGinkgoRecover(func() {
		log.Info("workloadType", zap.String("workloadType", workloadType))
		if strings.HasPrefix(workloadType, "sysbench") {
			oltppkg.GetTableAnalyzeInfo(ctxg, tc, caseCmdParms.SysbenchParms.Db, "sbtest11")
		}
	}))

	startTime := time.Now()
	g1, ctxg1 := errgroup.WithContext(ctxg)
	oltppkg.LogAndBy("Wait for workload balance on all tikvs.")
	oltppkg.WaitFor(ctxg, "Wait for warm up", 5*time.Minute)
	oltppkg.WaitForWorkloadBalance(ctxg1, tc, workloadType, g1, 2*time.Minute, 20*time.Minute, 0.8)
	Expect(g1.Wait()).Should(BeNil())

	oltppkg.LogAndBy("Monitor workload balance on all tikvs.")
	oltppkg.MonitorWorkloadBalance(ctxg1, tc, workloadType, g, runTime-time.Since(startTime), 0.8)

	Expect(g.Wait()).Should(BeNil())

	if workloadType == "sysbench_oltp_write_only" {
		_, currentSumSize, err := oltppkg.GetStoreSizeByType(tc, "used_size")
		Expect(err).Should(Succeed())
		sizeDiff := math.Abs(currentSumSize - initSumSize)
		log.Info("size", zap.Float64("initial-store-size", initSumSize), zap.Float64("current-store-size", currentSumSize), zap.Float64("size-difference", sizeDiff))
		// The difference between the capacity before updating and after updating shoule be less than 15G，which is estimated value
		// Expect(sizeDiff <= 15360).Should(BeTrue())
	}
}
