package main

import (
	"context"
	"time"

	"github.com/google/uuid"
	"github.com/pingcap/test-infra/caselib/pkg/host"
	"github.com/pingcap/test-infra/caselib/pkg/steps"
	"github.com/pingcap/test-infra/caselib/pkg/utils"
	"github.com/pingcap/test-infra/common/model/resource"
	apiresource "github.com/pingcap/test-infra/sdk/resource"
	_ "github.com/pingcap/test-infra/sdk/resource/impl/k8s"
	"go.uber.org/zap"
)

// This case test BR can tolerant TiDB compontent down in backup process
// In this case will scale-out TiKV & TiDB to 3 before Import data
// Will make TiKV&TiDB node unavailable while Backup
//
func BrNodeUnavailable() steps.Step {
	var (
		srcTidb            = &resource.ResourceHandle{}
		dstTidb            = &resource.ResourceHandle{}
		brHost             = &resource.ResourceHandle{}
		mcHost             = &resource.ResourceHandle{}
		periodTaskLifetime = 5 * time.Minute
		periodTaskCron     = 30 * time.Second
		backupOpts         = &host.BackupFullOpts{}
		mcRmOpts           = &host.McRmOpts{}
		lightningRes       = &resource.ResourceHandle{}
		opts               = &steps.LightningImportOpts{}
		uniq               = uuid.New().String()
		dropDatabases      string
	)

	return steps.
		NewBuilder().
		LoadEnv().
		LoadParamFromEnv(utils.ParamPrefix+"drop_databases", &dropDatabases).
		LoadResourceFromEnv(utils.ParamPrefix+"import_basic_opts", opts).
		LoadResourceFromEnv(utils.ResourcePrefix+"src_tidb", srcTidb).
		LoadResourceFromEnv(utils.ResourcePrefix+"dst_tidb", dstTidb).
		LoadResourceFromEnv(utils.ResourcePrefix+"lightning", lightningRes).
		LoadResourceFromEnv(utils.ResourcePrefix+"br", brHost).
		LoadResourceFromEnv(utils.ResourcePrefix+"mc", mcHost).
		LoadResourceFromEnv(utils.ParamPrefix+"br_opts", backupOpts).
		LoadResourceFromEnv(utils.ParamPrefix+"mc_rm_opts", mcRmOpts).
		DropDatabasesIfExists(srcTidb, &dropDatabases).
		LightningImport(opts, lightningRes, srcTidb).
		// Scale-out to 3 for each compontent
		// scale-in tidb
		ScaleTiDBcomponent(srcTidb, apiresource.TiDB, 3, 0).
		// scale-in tikv
		ScaleTiDBcomponent(srcTidb, apiresource.TiKV, 3, 0).
		// Parallel execute full backup, TiKV failure and TiDB failure
		NewUniqPath(&backupOpts.Storage, uniq).
		NewUniqPath(&mcRmOpts.Path, uniq).
		Parallel(
			steps.NewPeriodicalTask(periodTaskLifetime, periodTaskCron,
				steps.NewKVFailure(5*time.Second)),
			steps.NewPeriodicalTask(periodTaskLifetime, periodTaskCron,
				steps.NewTiDBFailure(5*time.Second)),
			steps.NewBrBackupFull(brHost, srcTidb, backupOpts),
		).
		DropUserDatabases(dstTidb).
		BrRestoreFull(brHost, dstTidb, backupOpts).
		CheckUserDatabasesCrc32(&backupOpts.Crc32Checksum, dstTidb).
		McRemove(mcRmOpts, mcHost).
		Build()
}

func main() {
	_, logger := utils.GetCtxAndLogger()
	ctx := steps.New(context.Background())
	if err := BrNodeUnavailable().Execute(ctx); err != nil {
		logger.Fatal("BrFullBasic failed", zap.Error(err))
	}
	logger.Info("BrFullBasic passed")
}
