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", "read_write_conflicts", "update conflict table name")
	totalRows            = flag.Int("rows", 10000, "total rows")
	writeMaxRespDuration = flag.Int("write-max-resp-dur", 600, "write max response duration in seconds")
	readMaxRespDuration  = flag.Int("read-max-resp-dur", 600, "read max response duration in seconds")
	concurrency          = flag.Int("concurrency", 100, "concurrency read worker count")
	writeSleepDuration   = flag.Int("write-sleep-dur", 1000, "write sleep duration between two queries in milliseconds")
	readSleepDuration    = flag.Int("read-sleep-dur", 10, "read 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("[read-write conflicts] start read-write 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("[read-write conflicts] 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("[read-write confict] prepare env failed, err %v", err)
	}

	db, err := util.OpenDB(dbDNS, *concurrency+1)
	if err != nil {
		client.Fatalf("[read-write 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("[read-write conflict] Got signal [%s] to exist.", sig)
		cancel()
		os.Exit(0)
	}()

	conflictsMaker, err := NewConflictsMaker(db, *database, *table, *totalRows, *writeMaxRespDuration,
		*readMaxRespDuration, *writeSleepDuration, *readSleepDuration, *concurrency)
	if err != nil {
		client.Fatalf("[read-write conflict] new conflict maker failed %v", err)
	}
	if err = conflictsMaker.Initialize(); err != nil {
		client.Fatalf("[read-write conflict] initial failed %v", err)
	}
	conflictsMaker.Execute(ctx)
}
