package tiup_upgrade

import (
	"database/sql"
	"fmt"
	"strings"

	"github.com/pingcap/log"

	_ "github.com/go-sql-driver/mysql"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
	. "github.com/pingcap/endless/pkg/workloadnode/tiup"
	"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"
	. "github.com/pingcap/endless/pkg/matcher"
	"go.uber.org/zap"
)

func GET_TIDB_CFG(
	cluster *TiUPCluster,
	workloadNode resource.WorkloadNode,
	flag string,
) {
	_, err := cluster.Display()
	if err != nil {
		Fail(err.Error())
	}
	dbURL, err := cluster.ServiceURL(resource.DBAddr)
	tidbIp := dbURL.Hostname()
	tidbPort := dbURL.Port()
	if err != nil {
		Fail(err.Error())
	}
	log.Info("db info", zap.String("url", dbURL.String()), zap.String("ip:", tidbIp), zap.String("port:", tidbPort))
	resultFile := fmt.Sprintf("tidb-%s.txt", flag)
	res, _, _, err := workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: "mkdir -p /root/result/;ls /root"}) // 直接用
	if err != nil {
		log.Fatal("err info:", zap.String("cmd exec fail:", err.Error()))
	}
	Expect(res).Should(ContainSubstring("result"))
	// tidbIp = "tiup-peer.testbed-py-w8b8k"
	// tidbPort = "3390"
	cmd := fmt.Sprintf("mysql -h %s -P %s -uroot -e 'select @@tidb_config\\G;' > /root/result/%s", tidbIp, tidbPort, resultFile)
	Try(workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: cmd}))

	res, _, _, err = workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: "ls -ltr /root/result/"}) // 直接用
	if err != nil {
		log.Fatal("err info:", zap.String("cmd exec fail:", err.Error()))
	}

	Expect(res).Should(ContainSubstring(resultFile))
}

func GET_PD_CFG(
	cluster *TiUPCluster,
	workloadNode resource.WorkloadNode,
	Version string,
	flag string,
) {
	pdURL, err := cluster.ServiceURL(resource.PDAddr)
	if err != nil {
		Fail(err.Error())
	}
	log.Info("pd info", zap.String("url", pdURL.String()), zap.String("ip:", pdURL.Host), zap.String("port:", pdURL.Port()))
	resultFile := fmt.Sprintf("pd-%s.txt", flag)
	pdstr := fmt.Sprintf("tiup ctl:%s pd -u %s config show all > /root/result/%s", Version, pdURL.String(), resultFile)
	Try(workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: pdstr}))
	pdstr = fmt.Sprintf("tiup ctl:%s pd -u %s scheduler config balance-hot-region-schedule >> /root/result/%s", Version, pdURL.String(), resultFile)
	Try(workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: pdstr}))
	pdstr = fmt.Sprintf("tiup ctl:%s pd -u %s scheduler config evict-leader-scheduler >> /root/result/%s", Version, pdURL.String(), resultFile)
	Try(workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: pdstr}))
	pdstr = fmt.Sprintf("tiup ctl:%s pd -u %s scheduler config grant-leader-scheduler >> /root/result/%s", Version, pdURL.String(), resultFile)
	Try(workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: pdstr}))
	pdstr = fmt.Sprintf("tiup ctl:%s pd -u %s scheduler config shuffle-region-scheduler >> /root/result/%s", Version, pdURL.String(), resultFile)
	Try(workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: pdstr}))
	res, _, _, err := workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: "ls -ltr /root/result/"}) // 直接用
	if err != nil {
		log.Fatal("err info:", zap.String("file not found:", err.Error()))
	}
	Expect(res).Should(ContainSubstring(resultFile))
}

func GET_SYSVAR_CFG(
	workloadNode resource.WorkloadNode,
	cluster *TiUPCluster,
	flag string,
) {
	dbURL, err := cluster.ServiceURL(resource.DBAddr)
	tidbIp := dbURL.Hostname()
	tidbPort := dbURL.Port()
	resultFile := fmt.Sprintf("sysvar-%s.txt", flag)
	cmd := fmt.Sprintf("mysql -h %s -P %s -uroot -e 'show variables;' > /root/result/%s", tidbIp, tidbPort, resultFile)
	Try(workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: cmd}))

	res, _, _, err := workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: "ls -ltr /root/result/"}) // 直接用
	if err != nil {
		log.Fatal("err info:", zap.String("file not found:", err.Error()))
	}
	Expect(res).Should(ContainSubstring(resultFile))
}

func GET_TIKV_CFG(
	workloadNode resource.WorkloadNode,
	cluster *TiUPCluster,
	flag string,
) {
	dbURL, err := cluster.ServiceURL(resource.DBAddr)
	tidbIp := dbURL.Hostname()
	tidbPort := dbURL.Port()
	resultFile := fmt.Sprintf("tikv-%s.txt", flag)
	cmd := fmt.Sprintf("mysql -h %s -P %s -uroot -e 'show config;' > /root/result/%s", tidbIp, tidbPort, resultFile)
	Try(workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: cmd}))

	res, _, _, err := workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: "ls -ltr /root/result/"}) // 直接用
	if err != nil {
		log.Fatal("err info:", zap.String("file not found:", err.Error()))
	}
	Expect(res).Should(ContainSubstring(resultFile))
}

func GET_TIFLASH_CFG(
	cluster *TiUPCluster,
	workloadNode resource.WorkloadNode,
	flag string,
) {
	var (
		tiflashstr string
	)

	resultFile := fmt.Sprintf("tiflash-%s.txt", flag)
	tiflashURL, err := cluster.ServiceURL(resource.TiFlashAddr)
	if err != nil {
		Fail(err.Error())
	}
	log.Info("tiflash info", zap.String("url", tiflashURL.String()), zap.String("ip:", tiflashURL.Hostname()), zap.String("port:", tiflashURL.Port()))
	tiflashstr = fmt.Sprintf("echo 'select * from settings' | curl 'http://%s:8123/?'  --data-binary @- > /root/result/%s", tiflashURL.Hostname(), resultFile)
	Try(workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: tiflashstr}))
	tiflashstr = fmt.Sprintf("curl 'http://%s:20292/config'|python -m json.tool >> /root/result/%s", tiflashURL.Hostname(), resultFile)
	Try(workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: tiflashstr}))

	res, _, _, err := workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: "ls -ltr /root/result/"}) // 直接用
	if err != nil {
		log.Fatal("err info:", zap.String("file not found:", err.Error()))
	}
	Expect(res).Should(ContainSubstring(resultFile))
}

func SET_SYSVAR(
	mycluster *TiUPCluster,
	cmd string,
) {
	db := Try(mycluster.GetDB("test")).(*sql.DB)
	defer db.Close()
	Try(db.Query(cmd))
	rows := Try(db.Query("show global variables like 'sql_mode';")).(*sql.Rows)
	defer rows.Close()
	for rows.Next() {
		var name string
		var value string
		Try(rows.Scan(&name, &value))
		log.Info("set variable:", zap.String("name", name), zap.String("value", value))
		Expect(value).ShouldNot(ContainSubstring("ONLY_FULL_GROUP_BY"))

	}

}

func GET_Grafana_Version(
	workloadNode resource.WorkloadNode,
) (res string) {
	res, _, _, err := workloadNode.Exec(resource.WorkloadNodeExecOptions{Command: "grep -m 1 version=  /tiup/deploy/grafana-13000/log/grafana.log | awk -F version= '{print $2}' | awk '{print $1}'"}) // 直接用
	if err != nil {
		log.Fatal("err info:", zap.String("get grafana version fail:", err.Error()))
	}
	if len(res) == 0 {
		Fail("get grafana version fail")
	}
	vers := strings.Split(strings.TrimSpace(res), ".")[0]
	log.Info("grafana version:", zap.String("version:", vers))
	return vers
}
