package gc

import (
	"context"
	"time"

	. "github.com/onsi/gomega"
	. "github.com/pingcap/endless/pkg/matcher"
	. "github.com/pingcap/endless/pkg/matcher/metrics"
	. "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_GC_STABILITY_DROP_001(
	ctx context.Context,
	tc resource.TiDBCluster,
	caseCmdParms oltppkg.CaseCmdParms,
	workloadRunParms oltppkg.WorkloadRunParms,
	br resource.BR,
	s3Parms oltppkg.S3Parms,
) {
	oltppkg.LogAndBy("run workload for one hour")
	var runTime time.Duration = 10 * time.Hour
	ctxAll, cancel := context.WithTimeout(ctx, runTime)
	defer cancel()
	g, ctxg := errgroup.WithContext(ctxAll)
	g.Go(WithGinkgoRecover(func() {
		workloadRunParms.Pause(ctxg, runTime)
	}))
	Try(oltppkg.RecreateDatabase(ctx, tc, caseCmdParms.SysbenchParms.Db))
	Try(oltppkg.RecreateDatabase(ctx, tc, caseCmdParms.TpccParms.Db))
	oltppkg.WaitFor(ctxg, "waiting for gc finished", 5*time.Minute)
	Eventually(func() float64 {
		_, sumSize, _ := oltppkg.GetStoreSizeByType(tc, "used_size")
		log.Info("sumsize", zap.Float64("sumSize", sumSize))
		return sumSize
	}, 60*time.Minute, 2*time.Minute).Should(BeNumerically("<", 3000))

	g.Go(WithGinkgoRecover(func() {
	Loop:
		for {
			select {
			case <-ctxg.Done():
				break Loop
			default:
			}
			BrRestoreDataWithoutCheck(ctxg, tc, br, s3Parms, caseCmdParms)
			threshhold := 0.1
			ConsistentlyWithMetrics(tc, 2*time.Minute).
				ShouldNot(
					SatisfyAny(
						StoreRegionSizeDifferentExceeds(threshhold).WithCtx(ctxg).For(1*time.Minute),
						StoreScoreDifferentExceeds(threshhold).WithCtx(ctxg).For(1*time.Minute),
					))

			Try(oltppkg.RecreateDatabase(ctx, tc, caseCmdParms.SysbenchParms.Db))
			Try(oltppkg.RecreateDatabase(ctx, tc, caseCmdParms.TpccParms.Db))
			oltppkg.WaitFor(ctxg, "waiting for gc finished", 5*time.Minute)
			Eventually(func() float64 {
				_, sumSize, _ := oltppkg.GetStoreSizeByType(tc, "used_size")
				log.Info("sumsize", zap.Float64("sumSize", sumSize))
				return sumSize
			}, 60*time.Minute, 2*time.Minute).Should(BeNumerically("<", 3000))
		}
	}))
	Expect(g.Wait()).Should(BeNil())
}
