// Copyright 2017 PingCAP, In
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
package main

import (
	"context"
	"flag"
	"math/rand"
	"os"
	"os/signal"
	"reflect"
	"runtime"
	"syscall"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"github.com/juju/errors"
	"github.com/pingcap/schrodinger/pkg/test_client"
)

var (
	dbName = flag.String("db", "test", "database name")
	test   = flag.String("test", "12345678", "test cases")
	debug  = flag.Bool("debug", false, "debug")
	mode   client.Mode
)

var tests = []func(db *DB) error{
	checkSplitTableRegion,
	checkDropTable,
	checkTruncateTable,
	checkInsertAndDeleteAll,
	checkInsertAndDeletePartial,
	checkDropIndex,
	checkShuffle,
	checkSpeed,
	checkCorrectness,
}

func main() {
	client.Info("[merge] start merge")
	flag.Parse()

	mode = client.ModeOnline

	if *debug {
		mode = client.ModeDev
	}
	ctx, cancel := context.WithCancel(context.Background())
	cli := client.New(ctx, mode)

	dbAddr := cli.TiDBs()[0]
	db, err := InitDB(dbAddr, *dbName)
	if err != nil {
		client.Fatalf("[merge] create db client error %v", err)
	}
	defer db.Close()

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

	err = InitHTTPClient(cli.PDs()[0], dbAddr)
	if err != nil {
		client.Fatalf("[merge] init http client error %v", err)
	}
	rand.Seed(time.Now().UnixNano())

	time.Sleep(5 * time.Minute)

	for _, ch := range *test {
		i := int(ch) - '1'
		if i >= len(tests) {
			client.Fatal("invalid test index")
		}
		fn := tests[i]
		client.Info(runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name())
		err = fn(db)
		if err != nil {
			client.Fatalf("test failed: %s", errors.ErrorStack(err))
		} else {
			client.Info("test pass!")
		}
	}
}
