package tikvrel

import (
	"context"
	"database/sql"
	"fmt"
	"strconv"
	"time"

	. "github.com/onsi/gomega"
	. "github.com/pingcap/endless/pkg/matcher"
	"github.com/pingcap/log"
	"go.uber.org/zap"
	"golang.org/x/sync/errgroup"

	// . "github.com/pingcap/endless/pkg/matcher/metrics"
	. "github.com/pingcap/endless/pkg/util"
	"github.com/pingcap/endless/pkg/workload"
	"github.com/pingcap/endless/testcase/oltp/oltppkg"
	"github.com/pingcap/endless/testcase/oltp/systemtest/ddl"

	// "github.com/pingcap/log"
	"github.com/pingcap/test-infra/sdk/core"
	"github.com/pingcap/test-infra/sdk/resource"
	_ "github.com/pingcap/test-infra/sdk/resource/impl/k8s"
)

func OLTP_BIG_VALUE_INSERT_REL(
	ctx core.TestContext,
	tc resource.MySQLCompatible,
	caseCmdParms oltppkg.CaseCmdParms,
	workloadRunParms oltppkg.WorkloadRunParms,
) {
	timestamp := strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
	dbName := fmt.Sprintf("%s_%s", "big_value", timestamp)
	Try(oltppkg.RecreateDatabase(ctx, tc, dbName))
	db := Try(ddl.ConnectDbWithTimeout(tc, dbName, "timeout=300m", "readTimeout=300m", "writeTimeout=300m")).(*sql.DB)
	defer db.Close()
	tikvRelOpts := &TiKVRelOptions{
		WarmUpTime:   5 * time.Hour,
		FaultType:    "restart",
		FaultNum:     1,
		RTO:          2 * time.Minute,
		RecoveryTime: 60 * time.Minute,
	}
	faultInjectNodeOrChaos1, faultInjectNodeOrChaos2, instanceIdList, falutInstanceIdList := tikvRelOpts.GetFaultInjectNodeOrChaos(ctx, tc)
	normalInstanceIdList := tikvRelOpts.getNormalTiKVInstance(instanceIdList, falutInstanceIdList)
	runTime, _ := tikvRelOpts.GetRunTimeAndCheckOffset(ctx, tc, caseCmdParms)
	log.Info("test will", zap.Duration("run", runTime))
	ctxAll, cancel := context.WithTimeout(ctx, runTime)
	defer cancel()
	g, gctx := errgroup.WithContext(ctxAll)

	w := workload.AppendWorkload{
		DB:          db,
		Concurrency: 256,
		Tables:      256,
		PadLength:   4000000,
	}
	log.Info("normal TiKV restart check during the whole process of running the case ")
	tikvRelOpts.tikvInstanceRestartCheck(gctx, tc, g, runTime, normalInstanceIdList)
	log.Info("check the tikv that is about to inject failure or restart during warm up")
	tikvRelOpts.tikvInstanceRestartCheck(gctx, tc, g, tikvRelOpts.WarmUpTime, falutInstanceIdList)
	tikvRelOpts.CommonCheckDuringCaseRunning(gctx, tc, g, runTime, nil, caseCmdParms)

	Try(w.Prepare())
	g.Go(WithGinkgoRecover(func() {
		w.Run(gctx)
		cancel()
	}))

	oltppkg.WaitFor(gctx, "Warm Up before inject fault", tikvRelOpts.WarmUpTime)
	log.Info("Fault Info", zap.Ints("all instanceId", instanceIdList),
		zap.Ints("will be injected fault InstanceId", falutInstanceIdList),
		zap.String("Fault Type", tikvRelOpts.FaultType))
	tikvRelOpts.InjectFaultAccordingToNum(gctx, tc, g, faultInjectNodeOrChaos1, faultInjectNodeOrChaos2)
	oltppkg.WaitFor(gctx, "wait for fault recover.", tikvRelOpts.FaultDuration+1*time.Minute)
	log.Info("TiKV restart check after failure or restart recovery")
	tikvRelOpts.tikvInstanceRestartCheck(gctx, tc, g, runTime, falutInstanceIdList)
	Expect(g.Wait()).Should(BeNil())
}
