package upgradepkg

import (
	"context"
	"database/sql"
	"fmt"
	"net/url"
	"time"

	_ "github.com/go-sql-driver/mysql"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/pingcap/endless/pkg/matcher"
	"github.com/pingcap/endless/pkg/workloadnode"
	"github.com/pingcap/log"
	"github.com/pingcap/test-infra/sdk/core"
	"github.com/pingcap/test-infra/sdk/resource"
	_ "github.com/pingcap/test-infra/sdk/resource/impl/k8s" // register k8s impl

	_ "github.com/pingcap/endless/pkg/client/tidb"
	"go.uber.org/zap"
)

var mysqlDsn = "mysql-peer:3306"

func must(err error) {
	if err != nil {
		Fail(err.Error())
	}
}

func WKLD_BANK_RUN(
	ctxwk core.TestContext,
	runtime string,
) {
	tcwk := ctxwk.Resource("tc").(resource.TiDBCluster)
	db := Try(tcwk.GetDB("")).(*sql.DB)
	defer db.Close()
	Try(db.Query("drop database if exists bank;"))
	Try(db.Query("create database bank;"))
	dbURL, err := tcwk.ServiceURL(resource.DBAddr)
	must(err)
	log.Info("dbDSN info:", zap.String("dbdsn:", dbURL.Host))

	gorandgen := ctxwk.Resource("wkload").(resource.WorkloadNode)
	dbDSN := dbURL.Host
	runCmd := fmt.Sprintf(`mkdir -p /root/wkload/precheck/;/tools/bank/run.sh init '%s' 100 60 bank > /root/wkload/precheck/bank.log 2>&1;`, dbDSN)
	duration := 10 * time.Hour
	ctx2, cancel := context.WithTimeout(ctxwk, duration)
	defer cancel()
	cmd1 := workloadnode.CommandContext(ctx2, runCmd)
	defer cmd1.Stop()
	Expect(cmd1.Run(gorandgen)).Should(BeNil())
	runCmd = fmt.Sprintf(`mkdir -p /root/wkload/postcheck/;nohup /tools/bank/run.sh run '%s' 100 %s bank > /root/wkload/postcheck/bank.log 2>&1`, dbDSN, runtime)
	cmd1 = workloadnode.CommandContext(ctx2, runCmd)
	defer cmd1.Stop()
	Expect(cmd1.Run(gorandgen)).Should(BeNil())

}
func WKLD_BANK_CHECK(
	ctxwk core.TestContext,
) {
	gorandgen := ctxwk.Resource("wkload").(resource.WorkloadNode)
	// dbDSN := "tiup-peer:3390"
	// check panic in result
	runCmd := fmt.Sprintf(`grep "fail" /tools/bank/nohup.out | wc -l`)
	duration := 10 * time.Hour
	ctx2, cancel := context.WithTimeout(ctxwk, duration)
	defer cancel()
	cmd1 := workloadnode.CommandContext(ctx2, runCmd)
	defer cmd1.Stop()
	Expect(cmd1.Run(gorandgen)).Should(BeNil())

}

func WKLD_TPTEST(
	ctxwk core.TestContext,
	flag string,
) {
	tcwk := ctxwk.Resource("tc").(resource.TiDBCluster)
	if flag == "precheck" {
		db := Try(tcwk.GetDB("test")).(*sql.DB)
		defer db.Close()
		Try(db.Query("drop database if exists tptest;"))
		Try(db.Query("create database tptest;"))
	}
	mysqlDB := "tptest"
	gorandgen := ctxwk.Resource("wkload").(resource.WorkloadNode)
	dbURL := Try(tcwk.ServiceURL(resource.DBAddr)).(*url.URL)
	log.Info("dbDSN info:", zap.String("dbdsn:", dbURL.Host))
	// dbDSN := "tiup-peer:3390"
	var runCmd string
	if flag == "precheck" {
		runCmd = fmt.Sprintf(`mkdir -p /root/wkload/precheck/;/tools/tp-test/tp-test/run.sh gen '%s' '%s' tptest %s > /root/wkload/precheck/tptest.log 2>&1`, dbURL.Host, mysqlDsn, mysqlDB)
	} else {
		runCmd = fmt.Sprintf(`mkdir -p /root/wkload/postcheck/;/tools/tp-test/tp-test/run.sh run '%s' '%s' tptest %s >> /root/wkload/postcheck/tptest.log 2>&1`, dbURL.Host, mysqlDsn, mysqlDB)
	}
	duration := 10 * time.Hour
	ctx2, cancel := context.WithTimeout(ctxwk, duration)
	defer cancel()
	cmd1 := workloadnode.CommandContext(ctx2, runCmd)
	defer cmd1.Stop()
	err := cmd1.Run(gorandgen)
	if err != nil {
		log.Info("run tptest result: ", zap.String("err:", err.Error()))
	}
	// check panic in log file
	runCmd = fmt.Sprintf(`grep "panic" /root/wkload/%s/tptest.log | wc -l`, flag)
	duration = 10 * time.Hour
	ctx2, cancel = context.WithTimeout(ctxwk, duration)
	defer cancel()
	cmd1 = workloadnode.CommandContext(ctx2, runCmd)
	defer cmd1.Stop()
	Expect(cmd1.Run(gorandgen)).Should(BeNil())
}

func WKLD_TPCH(
	ctxwk core.TestContext,
	flag string,
) {
	tcwk := ctxwk.Resource("tc").(resource.TiDBCluster)
	if flag == "precheck" {
		db := Try(tcwk.GetDB("test")).(*sql.DB)
		defer db.Close()
		Try(db.Query("drop database if exists tpch;"))
		Try(db.Query("create database tpch;"))
	}

	gorandgen := ctxwk.Resource("wkload").(resource.WorkloadNode)
	// dbip := "tiup-peer.testbed-upgrade-fthwr"
	// dbport := "3390"
	dbURL := Try(tcwk.ServiceURL(resource.DBAddr)).(*url.URL)
	log.Info("db info:", zap.String("dbIP:", dbURL.Hostname()), zap.String("db port:", dbURL.Port()))

	var runCmd string
	if flag == "precheck" {
		runCmd = fmt.Sprintf(`mkdir -p /root/wkload/precheck/;/tools/go-tpc/run.sh prepare %s %s 60s tpch > /root/wkload/precheck/tpch.log 2>&1`, dbURL.Hostname(), dbURL.Port())
	} else {
		runCmd = fmt.Sprintf(`mkdir -p /root/wkload/postcheck/;/tools/go-tpc/run.sh run %s %s 60s tpch > /root/wkload/postcheck/tpch.log 2>&1`, dbURL.Hostname(), dbURL.Port())
	}
	duration := 60 * time.Second
	ctx2, cancel := context.WithTimeout(ctxwk, duration)
	defer cancel()
	cmd1 := workloadnode.CommandContext(ctx2, runCmd)
	defer cmd1.Stop()
	err := cmd1.Run(gorandgen)
	if err != nil {
		log.Info("run tpch result: ", zap.String("err:", err.Error()))
	}
	// check panic in log file
	runCmd = fmt.Sprintf(`grep "panic" /root/wkload/%s/tpch.log | wc -l`, flag)
	duration = 10 * time.Hour
	ctx2, cancel = context.WithTimeout(ctxwk, duration)
	defer cancel()
	cmd1 = workloadnode.CommandContext(ctx2, runCmd)
	defer cmd1.Stop()
	Expect(cmd1.Run(gorandgen)).Should(BeNil())
}

func WKLD_RANDGEN(
	ctxwk core.TestContext,
	flag string,
) {
	tcwk := ctxwk.Resource("tc").(resource.TiDBCluster)
	if flag == "precheck" {
		db := Try(tcwk.GetDB("test")).(*sql.DB)
		defer db.Close()
		Try(db.Query("drop database if exists randgen;"))
		Try(db.Query("create database randgen;"))
	}

	gorandgen := ctxwk.Resource("wkload").(resource.WorkloadNode)
	dbURL := Try(tcwk.ServiceURL(resource.DBAddr)).(*url.URL)
	log.Info("dbDSN info:", zap.String("dbdsn:", dbURL.Host))
	// dbDSN := "tiup-peer:3390"
	mysqlDB := "randgen"
	var goRandgenCmd string
	if flag == "precheck" {
		goRandgenCmd = fmt.Sprintf(`mkdir -p /root/wkload/precheck/;/tools/go-randgen-master/run.sh gendata '%s' '%s' randgen %s > /root/wkload/precheck/randgen.log 2>&1`, dbURL.Host, mysqlDsn, mysqlDB)
	} else {
		goRandgenCmd = fmt.Sprintf(`mkdir -p /root/wkload/postcheck/;/tools/go-randgen-master/run.sh exec '%s' '%s' randgen %s>> /root/wkload/postcheck/randgen.log 2>&1`, dbURL.Host, mysqlDsn, mysqlDB)
	}
	duration := 10 * time.Hour
	ctx2, cancel := context.WithTimeout(ctxwk, duration)
	defer cancel()
	cmd1 := workloadnode.CommandContext(ctx2, goRandgenCmd)
	defer cmd1.Stop()
	err := cmd1.Run(gorandgen)
	if err != nil {
		log.Info("run randgen result: ", zap.String("err:", err.Error()))
	}

	// check panic in log file
	runCmd := fmt.Sprintf(`grep "panic" /root/wkload/%s/randgen.log | wc -l`, flag)
	duration = 10 * time.Hour
	ctx2, cancel = context.WithTimeout(ctxwk, duration)
	defer cancel()
	cmd1 = workloadnode.CommandContext(ctx2, runCmd)
	defer cmd1.Stop()
	Expect(cmd1.Run(gorandgen)).Should(BeNil())

}

func INIT_MYSQL(ctxwk core.TestContext) {
	mysqlCmd := ctxwk.Resource("mysql").(resource.MySQL)
	mysqlstr := fmt.Sprintf(" mysql -h mysql-peer -P3306 -uroot -e 'drop database if exists tptest;'")
	Try(mysqlCmd.Exec(resource.WorkloadNodeExecOptions{Command: mysqlstr}))
	mysqlstr = fmt.Sprintf(" mysql -h mysql-peer -P3306 -uroot -e 'create database tptest;'")
	Try(mysqlCmd.Exec(resource.WorkloadNodeExecOptions{Command: mysqlstr}))

	mysqlstr = fmt.Sprintf(" mysql -h mysql-peer -P3306 -uroot -e 'drop database if exists randgen;'")
	Try(mysqlCmd.Exec(resource.WorkloadNodeExecOptions{Command: mysqlstr}))
	mysqlstr = fmt.Sprintf(" mysql -h mysql-peer -P3306 -uroot -e 'create database randgen;'")
	Try(mysqlCmd.Exec(resource.WorkloadNodeExecOptions{Command: mysqlstr}))
}
func INIT_Cluster1(ctxwk core.TestContext) {
	tcwk := ctxwk.Resource("tc").(resource.TiDBCluster)
	// cluster = host.NewTiUPCluster(workloadNode, "tiup-peer", tiupTopo, "debug").WithCMDTimeout(60 * time.Minute)
	dbURL := Try(tcwk.ServiceURL(resource.DBAddr)).(*url.URL)
	tidbIp := dbURL.Hostname()
	tidbPort := dbURL.Port()
	log.Info("db info", zap.String("url", dbURL.String()), zap.String("ip:", tidbIp), zap.String("port:", tidbPort), zap.String("host:", dbURL.Host))
	db := Try(tcwk.GetDB("test")).(*sql.DB)
	defer db.Close()
	Try(db.Query("drop database if exists downDB;"))
	Try(db.Query("create database downDB;"))
	Try(db.Query("drop database if exists expidx;"))
	Try(db.Query("create database expidx;"))

}

func UTF_Feature(ctxutf core.TestContext, featureclass string, label string) {
	tcutf := ctxutf.Resource("tc").(resource.TiDBCluster)

	utf := ctxutf.Resource("utf").(resource.WorkloadNode)
	dbURL := Try(tcutf.ServiceURL(resource.DBAddr)).(*url.URL)
	log.Info("dbDSN info:", zap.String("dbdsn:", dbURL.Host))
	duration := 10 * time.Hour
	ctx2, cancel := context.WithTimeout(ctxutf, duration)
	defer cancel()
	cmd1 := workloadnode.CommandContext(ctx2, `pip install cryptography==36.0.2`)
	defer cmd1.Stop()
	err := cmd1.Run(utf)
	if err != nil {
		log.Info("sed result: ", zap.String("err:", err.Error()))
	}
	cmd2 := workloadnode.CommandContext(ctx2, `cp /automated-tests/cases/upgrade/run_feature.sh /automated-tests`)
	defer cmd2.Stop()
	err = cmd2.Run(utf)
	if err != nil {
		log.Info("sed result: ", zap.String("err:", err.Error()))
	}

	cmd3 := workloadnode.CommandContext(ctx2, `chmod 777 run_feature.sh`)
	defer cmd3.Stop()
	err = cmd3.Run(utf)
	if err != nil {
		log.Info("sed result: ", zap.String("err:", err.Error()))
	}

	utfCmd := fmt.Sprintf(`./run_feature.sh %s '%s'`, featureclass, label)

	cmd4 := workloadnode.CommandContext(ctx2, utfCmd)
	defer cmd4.Stop()
	err4 := cmd4.Run(utf)
	if err4 != nil {
		log.Info("run utf fail: ", zap.String("err:", err4.Error()), zap.String("feature:", featureclass))
	}

}
