package main

import (
	"flag"
	"os"
	"os/signal"
	"syscall"

	"fmt"
	"github.com/pingcap/schrodinger-test/util"
	"github.com/pingcap/schrodinger/pkg/test_client"
	"golang.org/x/net/context"
)

var (
	pwd             = flag.String("pwd", "", "password")
	database        = flag.String("db", "test", "database")
	table           = flag.String("table", "update_conflicts", "update conflict table name")
	totalRows       = flag.Int("rows", 1000, "total rows")
	maxRespDuration = flag.Int("max-resp-dur", 600, "max response duration in seconds")
	concurrency     = flag.Int("concurrency", 100, "concurrency read worker count")
	sleepDuration   = flag.Int("sleep-dur", 0, "sleep duration between two queries in milliseconds")
	runMode         = flag.String("run-mode", "online", "case mode, support values: online / dev, default value: online")
)

func prepareEnv(dbDNS string) error {
	db, err := util.OpenDB(dbDNS, 1)
	if err != nil {
		return err
	}
	defer db.Close()

	// Enable retry in conflicts case
	sql := "set @@global.tidb_retry_limit=10000; set @@global.tidb_disable_txn_auto_retry=0;"
	_, err = db.Exec(sql)
	return err
}

func main() {
	client.Info("[update conflicts] start update conflicts test")
	flag.Parse()

	ctx, cancel := context.WithCancel(context.Background())
	cli := client.New(ctx, func(mode string) (clientMode client.Mode) {
		switch client.Mode(mode) {
		case client.ModeOnline:
			clientMode = client.ModeOnline
		case client.ModeDev:
			clientMode = client.ModeDev
		default:
			client.Fatalf("[update conflict] Invalid mode: %v,support values: online / dev", mode)
		}
		client.Info("Mode:", clientMode)
		return clientMode
	}(*runMode))

	dbAddr := cli.TiDBService()
	dbDNS := fmt.Sprintf("root:%s@tcp(%s)/%s", *pwd, dbAddr, *database)
	client.Info("dbDNS: ", dbDNS)

	if err := prepareEnv(dbDNS); err != nil {
		client.Fatalf("[update confict] prepare env failed, err %v", err)
	}

	db, err := util.OpenDB(dbDNS, *concurrency)
	if err != nil {
		client.Fatalf("[update conflict] create db client err %v", err)
	}

	sc := make(chan os.Signal, 1)
	signal.Notify(sc,
		syscall.SIGHUP,
		syscall.SIGINT,
		syscall.SIGTERM,
		syscall.SIGQUIT)
	go func() {
		sig := <-sc
		client.Infof("[update conflict] Got signal [%s] to exist.", sig)
		cancel()
		os.Exit(0)
	}()

	availableDetector, err := NewUpdateConflictsMaker(db, *database, *table, *totalRows, *maxRespDuration, *sleepDuration, *concurrency)
	if err != nil {
		client.Fatalf("[update conflict] new update conflict detector failed %v", err)
	}
	if err = availableDetector.Initialize(); err != nil {
		client.Fatalf("[update conflict] initial failed %v", err)
	}
	availableDetector.Execute(ctx)
}
