package main

import (
	"fmt"
	"net/http"
	"strings"
	"time"

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

func replaceCat(cli *client.Client, version *Version) error {
	pdConfig := cli.CatConfig().PDConfig
	pdConfig.Version = version.Pd

	tikvConfig := cli.CatConfig().TiKVConfig
	tikvConfig.Version = version.Tikv

	tidbConfig := cli.CatConfig().TiDBConfig
	tidbConfig.Version = version.Tidb
	cat := &types.Cat{
		PDConfig:   pdConfig,
		TiDBConfig: tidbConfig,
		TiKVConfig: tikvConfig,
	}

	err := cli.ReplaceCat(cat)
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}

func upgradeCat(cli *client.Client, version *Version) error {
	pdConfig := cli.CatConfig().PDConfig
	pdConfig.Version = version.Pd

	tikvConfig := cli.CatConfig().TiKVConfig
	tikvConfig.Version = version.Tikv

	tidbConfig := cli.CatConfig().TiDBConfig
	tidbConfig.Version = version.Tidb
	newCat := &types.Cat{
		PDConfig:   pdConfig,
		TiDBConfig: tidbConfig,
		TiKVConfig: tikvConfig,
	}

	err := cli.UpgradeCat(newCat)
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}

func notifyUpgradeDDL(cli *client.Client, ip, component, operation string) error {
	tests := cli.GetTests()
	ddlIP := ""
	for _, test := range tests {
		if test.Name == notifyDDL && test.State == types.TestStateRunning {
			ddlIP = test.IP
			break
		}
	}

	if myutil.IsEmpty(ddlIP) {
		return errors.NotFoundf("ddl ip")
	}
	data, err := myutil.DoGet(http.DefaultClient, fmt.Sprintf("http://%s:8080/kill?ip=%s&component=%s&operation=%s", ddlIP, ip, component, operation))
	if err != nil {
		return errors.Trace(err)
	}
	if string(data) != "ok" {
		return errors.NotValidf("error %s", string(data))
	}
	return nil
}

func upgradeCatV2(cli *client.Client, version *Version) error {
	pds := cli.PDs()
	for _, pd := range pds {
		ip := strings.Split(pd, ":")[0]

		client.Debugf("start to upgrade pd %s", ip)

		err := upgradeVersion(cli, "pd", version.Pd, ip)
		if err != nil {
			return errors.Trace(err)
		}
		time.Sleep(waitInterval)
	}

	tikvs := cli.TiKVs()
	for _, tikv := range tikvs {
		ip := strings.Split(tikv, ":")[0]

		client.Debugf("start to upgrade tikv %s", ip)

		err := upgradeVersion(cli, "tikv", version.Tikv, ip)
		if err != nil {
			return errors.Trace(err)
		}
		time.Sleep(waitInterval)
	}

	tidbs := cli.TiDBs()
	for _, tidb := range tidbs {
		ip := strings.Split(tidb, ":")[0]
		isOwner, err := util.IsDDLOwner(ip)
		if err != nil {
			return errors.Trace(err)
		}

		client.Debugf("start to upgrade tidb %s", ip)
		if isOwner {
			client.Debugf("upgrade ddl owner")
		}

		err = upgradeVersion(cli, "tidb", version.Tidb, ip)
		if err != nil {
			return errors.Trace(err)
		}
		time.Sleep(waitInterval)
	}
	return nil
}

func stopTests(cli *client.Client) error {
	self := cli.SelfInfo()
	tests := cli.GetTests()
	for _, test := range tests {
		if test.ID == self.ID {
			continue
		}
		err := cli.StopTest(test.Name)
		if err != nil && !strings.Contains(err.Error(), "already closed") {
			return errors.Trace(err)
		}
	}
	return nil
}

func startTests(cli *client.Client) error {
	self := cli.SelfInfo()
	tests := cli.GetTests()
	for _, test := range tests {
		if test.Name == self.Name {
			continue
		}
		err := cli.StartTest(test.Name)
		if err != nil {
			return errors.Trace(err)
		}
	}
	return nil
}

func removeTests(cli *client.Client) error {
	self := cli.SelfInfo()
	tests := cli.GetTests()
	for _, test := range tests {
		if test.Name == self.Name {
			continue
		}
		err := cli.RemoveTest(test.Name)
		if err != nil {
			return errors.Trace(err)
		}
	}
	return nil
}
