package main

import (
	"context"
	"flag"
	"log"
	"time"

	"github.com/juju/errors"
	"github.com/pingcap/schrodinger/pkg/test_client"
)

var (
	dbName          = flag.String("db", "test", "database name")
	tidbConnCheck   = "select tidb_version();"
	tidbGeneralLog  = "set @@tidb_general_log = 1;"
	keepTime        = 30 * time.Minute
	emptyBackupName = "empty"

	threadCount = 20
)

// Pos stores pos information
type Pos struct {
	FileIndex int `json:"file_index"`
	LineIndex int `json:"line_index"`
}

var mode string

func init() {
	flag.StringVar(&mode, "mode", "random", "panic mode. can be full or random")
}

func main() {
	flag.Parse()
	if mode == "full" {
		threadCount = 1
	}
	ctx := context.Background()
	cli := client.New(ctx, client.ModeOnline)

	client.Info("[panicCheck] start backup cat...")
	if err := cli.BackupCat(emptyBackupName); err != nil {
		log.Fatalf("[panicCheck] backup empty cat failed, error: %v", err)
	}

	client.Info("threadCount:", threadCount)

	init := 0

	var (
		p   *Pos
		err error
	)
	if mode == "full" {
		p, err = getOrInitPos(cli)
		if err != nil {
			client.Fatalf("upload pos failed %+v", err)
		}
	} else {
		p = &Pos{}
	}

	for p.FileIndex < len(sqlCheckSet) {
		client.Debugf("pos %+v", p)
		if init != 0 {
			client.Info("start to revert cat to clean cat")
			if err = cli.RestoreCat(emptyBackupName); err != nil {
				client.Fatalf("recover cat from backup failed %v", errors.ErrorStack(err))
			}
		}

		init = 1
		if mode == "full" {
			if err := uploadPos(cli, p); err != nil {
				client.Errorf("upload pos failed %+v", err)
			}
		}

		client.Info("[panicCheck] start check, Time:", time.Now())
		hasPainc, data, err := executePanicCheck(ctx, cli, p, mode)
		if err != nil {
			client.ErrorStack(err)
		}
		if hasPainc {
			if mode == "full" {
				if err := uploadPos(cli, p); err != nil {
					client.Errorf("upload pos failed %+v", err)
				}
			}
			client.Fatal(data)
		}

		if mode == "full" {
			if err := uploadPos(cli, p); err != nil {
				client.Errorf("upload pos failed %+v", err)
			}
		}

		time.Sleep(15 * time.Second)
	}
}
