package main

import (
	"context"
	"fmt"
	"time"

	"github.com/juju/errors"
	"github.com/pingcap/schrodinger-test/util"
	"github.com/pingcap/schrodinger/buildbot/config"
	"github.com/pingcap/schrodinger/pkg/test_client"
	"github.com/pingcap/schrodinger/pkg/types"
	sutil "github.com/pingcap/schrodinger/util"
)

func upgradeVersion(cli *client.Client, repo string, version types.VersionInfo, targetIP string) error {
	// func upgradeVersion(repo string, version types.VersionInfo, targetIP string) error {
	hash, err := getRepoHash(repo, version)
	if err != nil {
		return errors.Trace(err)
	}

	err = replaceBinary(cli, version, repo, hash, targetIP, version.Value, version.Type)
	return errors.Trace(err)
}

func checkVersionAndPanic(originVersion types.VersionInfo, ip string, version string, typ string) error {
	db, err := util.OpenDB(fmt.Sprintf("root:@tcp(%s:4000)/test", ip), 20)
	if err != nil {
		return errors.Trace(err)
	}

	tidbVersion, err := util.GetTidbVersion(db)
	if err != nil {
		return errors.Trace(err)
	}

	if typ != "tag" {
		if tidbVersion == originVersion.Value {
			return errors.Errorf("target version %s is same with origin version %+v", tidbVersion, originVersion)
		}
		return nil
	}

	if tidbVersion != version {
		return errors.Errorf("target version not match %s:%s", tidbVersion, version)
	}
	return nil
}

func getRepoHash(repo string, version types.VersionInfo) (string, error) {
	if version.Type == "branch" || version.Type == "tag" {
		return sutil.GetHashByBranchAndTag(version.Value, version.Value, repo, config.GetBuildConfig().BaseConfig.DownloadAddr)
	}

	return version.Value, nil
}

func replaceBinary(cli *client.Client, version types.VersionInfo, repo string, hash string, targetIP string, tag string, typ string) error {
	err := downloadBinaryAndExtract(repo, hash, targetIP, false)
	if err != nil {
		err := downloadBinaryAndExtract(repo, hash, targetIP, true)
		if err != nil {
			return errors.Trace(err)
		}
	}

	err = notifyUpgradeDDL(cli, targetIP, repo, "stop")
	if err != nil {
		return errors.Trace(err)
	}

	err = restartBinary(targetIP, repo)
	if err != nil {
		return errors.Trace(err)
	}

	time.Sleep(notifyInterval)
	err = notifyUpgradeDDL(cli, targetIP, repo, "start")
	if err != nil {
		return errors.Trace(err)
	}

	if repo == "tidb" {
		return errors.Trace(checkVersionAndPanic(version, targetIP, tag, typ))
	}

	return nil
}

func downloadBinaryAndExtract(repo, hash, tagertIP string, isPr bool) error {
	pr := ""
	if isPr {
		pr = "/pr"
	}
	binaryURL := fmt.Sprintf("%s/download/builds/pingcap/%s%s/%s/centos7/%s-server.tar.gz",
		config.GetBuildConfig().BaseConfig.DownloadAddr, repo, pr, hash, repo)
	destPath := fmt.Sprintf("/preset_daemon/%s", repo)
	clearCmd := fmt.Sprintf("rm -f %s/%s-server.tar.gz", destPath, repo)
	downloadCmd := fmt.Sprintf("wget -P %s %s", destPath, binaryURL)
	extractCmd := fmt.Sprintf("cd %s && tar xvf %s-server.tar.gz", destPath, repo)
	checkCmd := fmt.Sprintf("%s/bin/%s-server -V", destPath, repo)
	cmd := fmt.Sprintf("%s && %s && %s && %s", clearCmd, downloadCmd, extractCmd, checkCmd)
	ctx := context.Background()
	err := util.RunWithRetry(ctx, 5, 5*time.Second, func() error {
		return util.PersistDaemonExec(tagertIP, cmd)
	})

	if err != nil {
		return errors.Trace(err)
	}
	return nil
}

func restartBinary(targetIP, repo string) error {
	err := util.DownPresetProcessForWait(targetIP, repo, 20*time.Minute)
	if err != nil {
		return errors.Trace(err)
	}

	time.Sleep(3 * time.Second)

	err = util.StartPresetProcess(targetIP, repo)
	if err != nil {
		return errors.Trace(err)
	}

	return nil
}
