package main

import (
	"database/sql"
	"flag"
	"os"
	"time"

	_ "github.com/go-sql-driver/mysql"
	"github.com/juju/errors"
	"github.com/ngaut/log"
	"github.com/pingcap/wormhole/test/dailytest"
	"github.com/pingcap/wormhole/test/util"
	"github.com/pingcap/wormhole/pkg/mysql"
)

const (
	// CREATEDATATUBE means create datatube for wormhole
	CREATEDATATUBE = "createDataTube"

	// LOADDATA means load data into mysql
	LOADDATA = "loadData"

	// TRUNCATE means truncate data in mysql
	TRUNCATE = "truncate"

	// CLEAR means drop database in mysql
	CLEAR = "clear"

	// CHECK means check data between mysql and tidb
	CHECK = "check"
)

func main() {
	cfg := NewConfig()
	err := cfg.Parse(os.Args[1:])
	switch errors.Cause(err) {
	case nil:
	case flag.ErrHelp:
		os.Exit(0)
	default:
		log.Errorf("parse cmd flags err %s\n", err)
		os.Exit(2)
	}

	TableSQLs := []string{`
create table if not exists ptest(
	a int primary key, 
	b double NOT NULL DEFAULT 2.0, 
	c varchar(10) NOT NULL, 
	d time unique
);
`,
		`
create table if not exists itest(
	a int, 
	b double NOT NULL DEFAULT 2.0, 
	c varchar(10) NOT NULL, 
	d time unique,
	PRIMARY KEY(a, b)
);
`,
		`
create table if not exists NTEST(
	a int, 
	b double NOT NULL DEFAULT 2.0, 
	c varchar(10) NOT NULL, 
	d time unique
);
`,
		`
create table if not exists mtest(
	a varchar(10) NOT NULL,
	b varchar(10) NOT NULL,
	c varchar(10) NOT NULL,
	d time unique,
	PRIMARY KEY(d)
);
`}

	log.Infof("jobType: %s", cfg.JobType)

	sourceDB, err := util.CreateDB(cfg.SourceDBCfg)
	if err != nil {
		log.Fatal(err)
	}
	defer util.CloseDB(sourceDB)

	targetDB, err := util.CreateDB(cfg.TargetDBCfg)
	if err != nil {
		log.Fatal(err)
	}
	defer util.CloseDB(targetDB)

	if cfg.JobType == CREATEDATATUBE {
		data, err := util.CreateDatasource(cfg.EtherUrl, &cfg.SourceDBCfg)
		if err != nil {
			log.Fatal(err)
		}

		time.Sleep(5 * time.Second)
		tables, err := mysql.ShowTables(sourceDB, cfg.SourceDBCfg.Name)
		if err != nil {
			log.Fatal(err)
		}
		err = util.CreateDataTube(cfg.EtherUrl, &cfg.SourceDBCfg, &cfg.TargetDBCfg, data, tables)
		if err != nil {
			log.Fatal(err)
		}
	}

	if cfg.JobType == LOADDATA {
		// generate insert/update/delete sqls and execute
		dailytest.RunDailyTest(cfg.SourceDBCfg, TableSQLs, cfg.WorkerCount, cfg.JobCount, cfg.Batch)
	}

	if cfg.JobType == TRUNCATE {
		// truncate test data
		dailytest.TruncateTestTable(cfg.SourceDBCfg, TableSQLs)
	}

	if cfg.JobType == CHECK {
		// diff the test schema
		if !checkSyncState(sourceDB, targetDB) {
			log.Fatal("sourceDB don't equal targetDB")
		}
		log.Info("test pass!!!")
	}

	if cfg.JobType == CLEAR {
		dailytest.DropTestTable(cfg.SourceDBCfg, TableSQLs)
	}
}

func checkSyncState(sourceDB, targetDB *sql.DB) bool {
	d := util.NewDiff(sourceDB, targetDB)
	ok, err := d.Equal()
	if err != nil {
		log.Fatal(err)
	}

	return ok
}
