package common

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/tidbcloud/idl/pbgen/proto/openapi/cm"
	"github.com/tidbcloud/qa-gourd/util"

	l4g "github.com/alecthomas/log4go"
	"github.com/dailymotion/allure-go"
	"github.com/gavv/httpexpect/v2"
	"github.com/stretchr/testify/assert"
)

const (
	LongestNameLength = 64
)

type ListPrivateEndpointsResp struct {
	Endpoints []*PrivateEndpoint `protobuf:"bytes,1,rep,name=endpoints,proto3" json:"endpoints,omitempty"`
}

type PrivateEndpoint struct {
	CloudProvider string `protobuf:"varint,1,opt,name=cloud_provider,json=cloudProvider,proto3" json:"cloud_provider,omitempty"`
	ClusterId     string `protobuf:"varint,2,opt,name=cluster_id,json=clusterId,proto3" json:"cluster_id,omitempty"`
	ClusterName   string `protobuf:"bytes,3,opt,name=cluster_name,json=clusterName,proto3" json:"cluster_name,omitempty"`
	RegionName    string `protobuf:"bytes,4,opt,name=region_name,json=regionName,proto3" json:"region_name,omitempty"`
	EndpointName  string `protobuf:"bytes,5,opt,name=endpoint_name,json=endpointName,proto3" json:"endpoint_name,omitempty"`
	Status        string `protobuf:"varint,6,opt,name=status,proto3,enum=openapi.PrivateEndpoint_Status" json:"status,omitempty"`
	Message       string `protobuf:"bytes,7,opt,name=message,proto3" json:"message,omitempty"`
	ServiceName   string `protobuf:"bytes,8,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"`
	ServiceStatus string `protobuf:"varint,9,opt,name=service_status,json=serviceStatus,proto3" json:"service_status,omitempty"`
	Id            string `protobuf:"varint,10,opt,name=id,proto3" json:"id,omitempty"`
}

type PrivateEndpointServiceResp struct {
	PrivateEndpointService *PrivateEndpointService `protobuf:"bytes,1,opt,name=private_endpoint_service,json=privateEndpointService,proto3" json:"private_endpoint_service,omitempty"`
}

type PrivateEndpointService struct {
	CloudProvider string   `protobuf:"varint,1,opt,name=cloud_provider,json=cloudProvider,proto3" json:"cloud_provider,omitempty"`
	Name          string   `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
	Status        string   `protobuf:"varint,3,opt,name=status,proto3" json:"status,omitempty"`
	DnsName       string   `protobuf:"bytes,4,opt,name=dns_name,json=dnsName,proto3" json:"dns_name,omitempty"`
	Port          int32    `protobuf:"varint,5,opt,name=port,proto3" json:"port,omitempty"`
	AzIds         []string `protobuf:"bytes,6,rep,name=az_ids,json=azIds,proto3" json:"az_ids,omitempty"`
}

type Accesspoint struct {
	Id                 string                             `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
	ProjectId          string                             `protobuf:"varint,2,opt,name=project_id,json=projectId,proto3" json:"project_id,omitempty"`
	ClusterId          string                             `protobuf:"varint,3,opt,name=cluster_id,json=clusterId,proto3" json:"cluster_id,omitempty"`
	DisplayName        string                             `protobuf:"bytes,4,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"`
	TidbNodeQuantity   int32                              `protobuf:"varint,5,opt,name=tidb_node_quantity,json=tidbNodeQuantity,proto3" json:"tidb_node_quantity,omitempty"`
	PublicEndpoint     *cm.Accesspoint_PublicEndpoint     `protobuf:"bytes,6,opt,name=public_endpoint,json=publicEndpoint,proto3" json:"public_endpoint,omitempty"`
	VpcPeeringEndpoint *cm.Accesspoint_VpcPeeringEndpoint `protobuf:"bytes,7,opt,name=vpc_peering_endpoint,json=vpcPeeringEndpoint,proto3" json:"vpc_peering_endpoint,omitempty"`
	PrivateEndpoint    *Accesspoint_PrivateEndpoint       `protobuf:"bytes,8,opt,name=private_endpoint,json=privateEndpoint,proto3" json:"private_endpoint,omitempty"`
}

type Accesspoint_PrivateEndpoint struct {
	PrivateLinkService *Accesspoint_PrivateEndpoint_PrivateLinkService `protobuf:"bytes,1,opt,name=private_link_service,json=privateLinkService,proto3" json:"private_link_service,omitempty"`
	Host               string                                          `protobuf:"bytes,2,opt,name=host,proto3" json:"host,omitempty"`
	Port               int32                                           `protobuf:"varint,3,opt,name=port,proto3" json:"port,omitempty"`
	AzIds              []string                                        `protobuf:"bytes,4,rep,name=az_ids,json=azIds,proto3" json:"az_ids,omitempty"`
}

type Accesspoint_PrivateEndpoint_PrivateLinkService struct {
	ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"`
	Status      string `protobuf:"json:"status,omitempty"`
}

type ListAccesspointsResp struct {
	Items []*Accesspoint `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"`
	Total int32          `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"`
}

func DeleteIdInMap(clusterId string) {
	for _, cluster := range DeleteClusterIdList {
		if cluster["clusterId"] == clusterId {
			cluster["deleted"] = "1"
		}
	}

}

// get cluster's profile from a specific cluster
func GetClusterProfile(t assert.TestingT, orgId, projectId, clusterId string) (bool, string, string, string, int, string, int, int, string, int, int) {
	dbassRequestInfo = GetDbassRequestInfo(t)
	if orgId == "" {
		orgId = dbassRequestInfo.CommonEnv.OrgId
	}
	if projectId == "" {
		projectId = dbassRequestInfo.CommonEnv.ProjectId
	}
	// get cluster info
	clusterPathParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}
	getClusterInfoResp := dbassRequestInfo.DbassRequest(t, "getClusterInfo", nil, clusterPathParam, nil, nil)
	isDevTier := getClusterInfoResp.JSON().Path("$.cluster.is_dev_tier").Boolean().Raw()
	provider := getClusterInfoResp.JSON().Path("$.cluster.provider").String().Raw()
	region := getClusterInfoResp.JSON().Path("$.cluster.region").String().Raw()
	// tidb
	tidbProfileId := getClusterInfoResp.JSON().Object().Value("cluster").Object().Value("cluster_components").Object().Value("tidb").Object().Value("node_profile").Object().Value("name").String().Raw()
	tidbCount := int(getClusterInfoResp.JSON().Object().Value("cluster").Object().Value("cluster_components").Object().Value("tidb").Object().Value("replicas").Number().Raw())
	// tikv
	tikvProfileId := getClusterInfoResp.JSON().Object().Value("cluster").Object().Value("cluster_components").Object().Value("tikv").Object().Value("node_profile").Object().Value("name").String().Raw()
	tikvStorage := int(getClusterInfoResp.JSON().Object().Value("cluster").Object().Value("cluster_components").Object().Value("tikv").Object().Value("node_profile").Object().Value("storage_gi").Number().Raw())
	tikvCount := int(getClusterInfoResp.JSON().Object().Value("cluster").Object().Value("cluster_components").Object().Value("tikv").Object().Value("replicas").Number().Raw())

	// whether there is tiflash
	component := getClusterInfoResp.JSON().Object().Value("cluster").Object().Value("cluster_components").Object().Raw()
	// tiflash
	var tiflashProfileId string
	var tiflashCount, tiflashStorage int
	if component["tiflash"] != nil {
		// if has tiflash component
		tiflashProfileId = getClusterInfoResp.JSON().Object().Value("cluster").Object().Value("cluster_components").Object().Value("tiflash").Object().Value("node_profile").Object().Value("name").String().Raw()
		tiflashStorage = int(getClusterInfoResp.JSON().Object().Value("cluster").Object().Value("cluster_components").Object().Value("tiflash").Object().Value("node_profile").Object().Value("storage_gi").Number().Raw())
		tiflashCount = int(getClusterInfoResp.JSON().Object().Value("cluster").Object().Value("cluster_components").Object().Value("tiflash").Object().Value("replicas").Number().Raw())
	}
	return isDevTier, provider, region, tidbProfileId, tidbCount, tikvProfileId, tikvStorage, tikvCount, tiflashProfileId, tiflashCount, tiflashStorage
}

func GetProfileIds(t assert.TestingT, provider, region, orgId, projectId, clusterId string, isDevTier bool) (int, int, string, string, string, int, string, string, string) {
	var tidbCpu, tikvCpu, tiflashCpu, tidbMem, tikvMem, tiflashMem string
	if orgId == "" {
		orgId = dbassRequestInfo.CommonEnv.OrgId
	}
	if projectId == "" {
		projectId = dbassRequestInfo.CommonEnv.ProjectId
	}
	if region == "" {
		if provider == "aws" {
			region = dbassRequestInfo.CommonEnv.AwsRegion
		} else if provider == "gcp" {
			region = dbassRequestInfo.CommonEnv.GcpRegion
		}

	}
	if clusterId == "" {
		tidbCpu = dbassRequestInfo.CommonEnv.TidbCpu
		tikvCpu = dbassRequestInfo.CommonEnv.TikvCpu
		tiflashCpu = dbassRequestInfo.CommonEnv.TiflashCpu
		tidbMem = dbassRequestInfo.CommonEnv.TidbMem
		tikvMem = dbassRequestInfo.CommonEnv.TikvMem
		tiflashMem = dbassRequestInfo.CommonEnv.TiflashMem
	} else {
		clusterPathParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}
		getClusterInfoResp := dbassRequestInfo.DbassRequest(t, "getClusterInfo", nil, clusterPathParam, nil, nil)

		// tidb
		tidbCpu = getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tidb.node_profile.compute.cpu").String().Raw()
		tidbMem = getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tidb.node_profile.compute.memory_mi").String().Raw()

		tikvCpu = getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tikv.node_profile.compute.cpu").String().Raw()
		tikvMem = getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tikv.node_profile.compute.memory_mi").String().Raw()

		if dbassRequestInfo.CommonEnv.TiflashCpu != "" {
			tiflashCpu = getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tiflash.node_profile.compute.cpu").String().Raw()
			tiflashMem = getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tiflash.node_profile.compute.memory_mi").String().Raw()
		}

	}
	profileBody := NewNodeProfilesRequest(isDevTier, orgId, provider, region)

	profilePathParam := map[string]string{"org_id": orgId, "project_id": projectId}
	getProfilesResp := dbassRequestInfo.DbassRequest(t, "getProfiles", profileBody, profilePathParam, nil, nil)
	tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId, is_arm, tidbScaleProfileId, tikvScaleProfileId, tiflashScaleProfileId := GetProfileIdAndStorage(getProfilesResp, tidbCpu, tikvCpu, tiflashCpu, tidbMem, tikvMem, tiflashMem, isDevTier)

	l4g.Info("getProfilesResp:%v, tikvStorage:%d, tiflashStorage:%d, tidbProfileId:%s, tikvProfileId:%s, tiflashProfileId:%s", getProfilesResp.JSON().Raw(), tikvStorage,
		tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId)
	allure.Step(
		allure.Story("CheckCreateCluster"),
		allure.Description(fmt.Sprintf("getProfiles, body:%v, tikvStorage:%d, tiflashStorage:%d, tidbProfileId:%s, tikvProfileId:%s, tiflashProfileId:%s",
			profileBody, tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId)),
		allure.Action(func() {
			getProfilesResp.Status(StatusOK)
		}))
	return tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId, is_arm, tidbScaleProfileId, tikvScaleProfileId, tiflashScaleProfileId
}

func CreateCluster(t assert.TestingT, provider string, isDevTier bool, tidb_count,
	tikv_count, tifish_count int, projectId string, primaryClsterId, secondaryRegion, region string, spendLimits int) (string, map[string]float64, string) {
	dbassRequestInfo = GetDbassRequestInfo(t)
	orgId := dbassRequestInfo.CommonEnv.OrgId
	tiflashCpu := dbassRequestInfo.CommonEnv.TiflashCpu
	port := dbassRequestInfo.CommonEnv.Port
	//var is_arm int
	//var auto_project = 1
	if projectId == "" {
		projectId = dbassRequestInfo.CommonEnv.ProjectId
		//auto_project = 0
	}

	if tiflashCpu == "" && !isDevTier {
		tifish_count = 0
	}

	// Set cluster name with timestamp & provider & region & run user's name
	var ClusterNameSuffix string
	if RunUser != "" {
		ClusterNameSuffix = "-" + strings.Replace(RunUser, ".", "--", -1)
	}
	name := "SceneAuto-" + GenTempName() + provider + region + ClusterNameSuffix
	if len(name) > LongestNameLength {
		name = name[len(name)-LongestNameLength:] // if the name is super long, just use the last 64 chars.
	}
	l4g.Info("Create Cluster, cluster's name is : %s", name)

	//获取profileId
	var tikvStorage, tiflashStorage int
	var tidbProfileId, tikvProfileId, tiflashProfileId, tidbScaleProfileId, tikvScaleProfileId, tiflashScaleProfileId string
	if primaryClsterId == "" {
		//clusterStatus = "NORMAL"
		tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId, _, tidbScaleProfileId, tikvScaleProfileId, tiflashScaleProfileId =
			GetProfileIds(t, provider, region, orgId, projectId, "", isDevTier)
	}

	//创建集群
	create_cluster_price := make(map[string]float64)
	var createClusterInfo *CreateClus
	if primaryClsterId == "" {
		createClusterInfo = NewCreateClusterInfo(orgId, provider, name, region, isDevTier,
			tidb_count, tikv_count, tifish_count, tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId, "", port, "", spendLimits)
		create_cluster_price["price"], create_cluster_price["compute_price"], create_cluster_price["storage_price"] = Get3Price(t, provider, region, tidb_count, tikv_count, tifish_count, tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId, isDevTier)

	} else if provider == "aws" {
		createClusterInfo = NewCreateClusterInfo(orgId, provider, name, secondaryRegion, isDevTier,
			tidb_count, tikv_count, tifish_count, AwsTikvStorage, AwsTiflashStorage, AwsTidbProfileId, AwsTikvProfileId, AwsTiflashProfileId, primaryClsterId, port, "", spendLimits)
		create_cluster_price["price"], create_cluster_price["compute_price"], create_cluster_price["storage_price"] = Get3Price(t, provider, region, tidb_count, tikv_count, tifish_count, AwsTikvStorage, AwsTiflashStorage, AwsTidbProfileId, AwsTikvProfileId, AwsTiflashProfileId, isDevTier)

	} else if provider == "gcp" {
		createClusterInfo = NewCreateClusterInfo(orgId, provider, name, secondaryRegion, isDevTier,
			tidb_count, tikv_count, tifish_count, GcpTikvStorage, GcpTiflashStorage, GcpTidbProfileId, GcpTikvProfileId, GcpTiflashProfileId, primaryClsterId, port, "", spendLimits)
		create_cluster_price["price"], create_cluster_price["compute_price"], create_cluster_price["storage_price"] = Get3Price(t, provider, region, tidb_count, tikv_count, tifish_count, GcpTikvStorage, GcpTiflashStorage, GcpTidbProfileId, GcpTikvProfileId, GcpTiflashProfileId, isDevTier)
	}

	pathparam := map[string]string{"org_id": orgId, "project_id": projectId}
	createClusterResp := dbassRequestInfo.DbassRequest(t, "createCluster", createClusterInfo, pathparam, nil, nil)

	l4g.Info("createClusterResp:%s, body is %s, pathparam is %s", createClusterResp.JSON().Raw(),
		createClusterInfo, pathparam)
	var id string
	allure.Step(
		allure.Story("CheckCreateCluster"),
		allure.Description(fmt.Sprintf("create cluster, body:%v, pathparam:%s, createClusterResp:%s", createClusterInfo, pathparam, createClusterResp.JSON().Raw())),
		allure.Action(func() {
			createClusterResp.Status(StatusOK).JSON().Object().Keys().Contains("id")
			id = createClusterResp.JSON().Path("$.id").String().Raw()
			time.Sleep(time.Second * 10)
			var getClusterListResp *httpexpect.Response
			getClusterListResp = dbassRequestInfo.DbassRequest(t, "getClusterList", nil, pathparam, nil, nil)
			l4g.Info("getClusterListResp is: %s", getClusterListResp.JSON().Raw().(map[string]interface{}))
			CheckClusterInGetClusters(getClusterListResp, id)
		}))

	if primaryClsterId == "" {
		if isDevTier {
			DevTierTikvStorage, DevTierTiflashStorage, DevTierTidbProfileId, DevTierTikvProfileId, DevTierTiflashProfileId = tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId
		} else if provider == "aws" {
			AwsTikvStorage, AwsTiflashStorage, AwsTidbProfileId, AwsTikvProfileId, AwsTiflashProfileId, AwsScaleTidbProfileId, AwsScaleTikvProfileId, AwsScaleTiflashProfileId = tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId, tidbScaleProfileId, tikvScaleProfileId, tiflashScaleProfileId
		} else if provider == "gcp" {
			GcpTikvStorage, GcpTiflashStorage, GcpTidbProfileId, GcpTikvProfileId, GcpTiflashProfileId, GcpScaleTidbProfileId, GcpScaleTikvProfileId, GcpScaleTiflashProfileId = tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId, tidbScaleProfileId, tikvScaleProfileId, tiflashScaleProfileId
		}
	}

	return id, create_cluster_price, name
}

func CheckClusterStatus(t assert.TestingT, projectId, clusterId, path, expectStatus string, maxRound int) (string,
	int64, int64, int64) {
	var preparingBeginTime, lunchingBeginTime, normalBeginTime int64
	dbassRequestInfo = GetDbassRequestInfo(t)
	orgId := dbassRequestInfo.CommonEnv.OrgId
	//var auto_project = 1
	if projectId == "" {
		projectId = dbassRequestInfo.CommonEnv.ProjectId
		//auto_project = 0

	}
	var getClusterInfoResp *httpexpect.Response
	var status string
	clusterPathParam := map[string]string{"org_id": orgId, "cluster_id": clusterId, "project_id": projectId}

	for round := 0; round <= 2*maxRound; round += 1 {
		getClusterInfoResp = dbassRequestInfo.DbassRequest(t, "getClusterInfo", nil, clusterPathParam, nil, nil)
		if getClusterInfoResp.JSON().Path("$.base_resp.err_code").String().Raw() != "0" {
			//cluster error
			return "", 0, 0, 0
		}

		l4g.Info("getClusterInfoResp is: %s, round is: %d", getClusterInfoResp.JSON().Raw(), round)
		if getClusterInfoResp.JSON().Path("$.cluster.create_progress").String().Raw() == "PREPARING" && preparingBeginTime == 0 {
			preparingBeginTime = time.Now().Unix()
			l4g.Info("preparingBeginTime:%d", preparingBeginTime)
		} else if getClusterInfoResp.JSON().Path("$.cluster.create_progress").String().Raw() == "LAUNCHING" && lunchingBeginTime == 0 {

			lunchingBeginTime = time.Now().Unix()
			l4g.Info("lunchingBeginTime:%d", lunchingBeginTime)
		}
		if getClusterInfoResp.JSON().Path(path).String().Raw() == expectStatus {
			break
		}
		time.Sleep(time.Second * 30)
	}
	status = getClusterInfoResp.JSON().Path(path).String().Raw()
	allure.Step(
		allure.Story("CheckCreateCluster"),
		allure.Description(fmt.Sprintf("get cluster status, check the status is normal. "+
			"Expected value：%s, Actual value: %s, clusterId is:%s", expectStatus, status, clusterId)),
		allure.Action(func() {
			getClusterInfoResp.JSON().Path(path).String().Equal(expectStatus)
		}))

	isDevTier := getClusterInfoResp.JSON().Path("$.cluster.is_dev_tier").Boolean().Raw()
	if isDevTier {
		region := getClusterInfoResp.JSON().Path("$.cluster.region").String().Raw()
		dbassRequestInfo.CommonEnv.DevTierRegion = region
	}

	return status, preparingBeginTime, lunchingBeginTime, normalBeginTime
}

func AddTrafficFilter(t assert.TestingT, orgId, projectId, clusterId string, disablePublicLB bool) {
	dbassRequestInfo = GetDbassRequestInfo(t)
	requireSecureTransport := dbassRequestInfo.CommonEnv.RequireSecureTransport
	clusterPathParam := map[string]string{"org_id": orgId, "cluster_id": clusterId, "project_id": projectId}
	filter := NewTrafficFilter(dbassRequestInfo.CommonEnv.Cicr, "test", disablePublicLB)
	addFilterResp := dbassRequestInfo.DbassRequest(t, "addFilter", filter, clusterPathParam, nil, nil)
	l4g.Info("addFilterResp:", addFilterResp.JSON().Raw())
	allure.Step(allure.Description(fmt.Sprintf("add traffic filter, body:%v, pathParam:%s, addFilterResp:%s", filter, clusterPathParam, addFilterResp.JSON().Raw())),
		allure.Action(func() {
			addFilterResp.Status(StatusOK)
		}))
	if requireSecureTransport == "on" {
		l4g.Info("begin SET GLOBAL require_secure_transport = ON")
		getClusterInfoResp := dbassRequestInfo.DbassRequest(t, "getClusterInfo", nil, clusterPathParam, nil, nil)
		tidbAddress := getClusterInfoResp.JSON().Path("$.cluster.endpoint.address").String().Raw()
		tidbPort := int64(getClusterInfoResp.JSON().Path("$.cluster.endpoint.port").Raw().(float64))
		db, _ := ConnectTidbUseTLS(tidbAddress, tidbPort, dbassRequestInfo.CommonEnv.DbPassword, database, "root")
		CreateTable(db, secureTransportSQL)
	}
}

func CheckCreateCluster(t assert.TestingT, provider string, isDevTier bool, tidb_count,
	tikv_count, tifish_count int, projectId string, primaryClsterId, secondaryRegion, region string) string {
	//加载配置
	//var region string
	dbassRequestInfo = GetDbassRequestInfo(t)
	orgId := dbassRequestInfo.CommonEnv.OrgId
	url := dbassRequestInfo.CommonEnv.MysqlUrl
	password := dbassRequestInfo.CommonEnv.MysqlPassword
	ec2Host := dbassRequestInfo.CommonEnv.Ec2Host
	cerPath := dbassRequestInfo.CommonEnv.CerPath
	loginUser := dbassRequestInfo.CommonEnv.LoginUser
	profileType := dbassRequestInfo.CommonEnv.TikvCpu + "c"

	if region == "" {
		if provider == "aws" {
			region = dbassRequestInfo.CommonEnv.AwsRegion
		} else {
			region = dbassRequestInfo.CommonEnv.GcpRegion
		}
		if isDevTier == true {
			region = dbassRequestInfo.CommonEnv.DevTierRegion
		}
	}

	//var auto_project = 1
	if projectId == "" {
		projectId = dbassRequestInfo.CommonEnv.ProjectId
		//auto_project = 0
	}
	hasTiflash := 1
	if dbassRequestInfo.CommonEnv.TiflashCpu == "" && !isDevTier {
		hasTiflash = 0
	}

	id, _, _ := CreateCluster(t, provider, isDevTier, tidb_count, tikv_count, tifish_count, projectId, primaryClsterId, secondaryRegion, region, 0)

	if id == "0" || id == "" {
		return ""
	}

	createClusterStartTime := time.Now().Unix()
	createTime := time.Now().Format("2006-01-02 15:04:05")
	var isTimeout int
	UpdatePassword(t, projectId, id, dbassRequestInfo.CommonEnv.DbPassword)

	//已有cluster查询
	status, preparingBeginTime, lunchingBeginTime, normalBeginTime := CheckClusterStatus(t, projectId, id, "$.cluster.status", "NORMAL", 60)
	if status == "CREATING" || status == "" {
		isTimeout = 1
		return ""
	}

	if !isDevTier {
		AddTrafficFilter(t, orgId, projectId, id, false)
	}
	normalBeginTime = time.Now().Unix()
	infraProvider := GetProvider(ec2Host, cerPath, loginUser, projectId, region, Envn)
	l4g.Info("infraProvider:%s", infraProvider)

	var initialTime, prepareTime, lunchTime int64

	if primaryClsterId == "" {
		totalTime := normalBeginTime - createClusterStartTime
		if preparingBeginTime == 0 {
			initialTime = 0
			prepareTime = lunchingBeginTime - createClusterStartTime
		} else {
			initialTime = preparingBeginTime - createClusterStartTime
			if lunchingBeginTime == 0 {
				prepareTime = 0
				lunchTime = normalBeginTime - preparingBeginTime
			} else {
				prepareTime = lunchingBeginTime - preparingBeginTime
				lunchTime = normalBeginTime - lunchingBeginTime
			}
		}

		urldata := strings.Split(url, ":")
		port, _ := strconv.ParseInt(urldata[1], 10, 64)
		var isDevTierInt int
		if isDevTier {
			isDevTierInt = 1
		}

		InsertClusterCreateTimeToMysql(urldata[0], port, password, "case_manager", Envn, id, int(totalTime),
			int(initialTime), int(prepareTime), int(lunchTime), isTimeout, createTime, isDevTierInt, provider,
			profileType, infraProvider, hasTiflash, isarm)

	}

	//hostData := strings.Split(dbassRequestInfo.CommonEnv.MysqlUrl, ":")
	//port1, _ := strconv.Atoi(hostData[1])
	//InsertProjectIdToMysql(hostData[0], int64(port1), dbassRequestInfo.CommonEnv.MysqlPassword, "case_manager", id, auto_project, Envn)
	DeleteClusterIdList = append(DeleteClusterIdList, map[string]string{"projectId": projectId, "clusterId": id, "delete": "0"})
	time.Sleep(time.Second * 60)
	return id
	/*if getClusterInfoResp.JSON().Path("$.status").String().Raw() == "NORMAL"{
		return pathparam, clusterPathParam, nil
	}else{
		return nil, nil, errors.New("create cluster failed")
	}*/
}

func CheckClusterInfoByDetail(t assert.TestingT, clusterId string, tifish_count,
	tikv_storage, tiflash_storage int, tidb_nodesize, tikv_nodesize, tiflash_nodesize, projectId string) {
	dbassRequestInfo = GetDbassRequestInfo(t)
	orgId := dbassRequestInfo.CommonEnv.OrgId
	if dbassRequestInfo.CommonEnv.TiflashCpu == "" {
		tifish_count = 0
		tiflash_storage = 0
	}
	if projectId == "" {
		projectId = dbassRequestInfo.CommonEnv.ProjectId
	}
	//projectId = dbassRequestInfo.CommonEnv.ProjectId

	//查看集群的详细信息
	clusterPathParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}
	//getClusterInfoResp := dbassRequestInfo.DbassRequest(t, "getClusterInfo", nil, clusterPathParam, nil, nil)
	//name := getClusterInfoResp.JSON().Path("$.cluster.name").String().Raw()

	getClusterInfoResp := dbassRequestInfo.DbassRequest(t, "getClusterInfo", nil, clusterPathParam, nil, nil)
	var actual_tiflash_nodesize string
	var actual_tiflash_storage float64
	if tifish_count != 0 {
		actual_tiflash_nodesize = getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tiflash.node_profile.name").String().Raw()
		actual_tiflash_storage = getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tiflash.node_profile.storage_gi").Number().Raw()
	}
	allure.Step(
		allure.Story("CheckCreateCluster"),
		allure.Description(fmt.Sprintf("get cluster node Info, Expect tidb.node_profile.name:%s, "+
			"Actual tidb.node_profile.name:%s, Expect tikv.node_profile.name:%s, Actual tikv.node_profile.name:%s"+
			", Expect tiflash.node_profile.name:%s, Actual tiflash.node_profile.name:%s, "+
			"Expect tikv.storage_gi:%d, Actual tikv.storage_gi:%s, Expect tiflash.storage_gi:%d, Actual tiflash.storage_gi:%f",
			tidb_nodesize, getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tidb.node_profile.name").Raw(),
			tikv_nodesize, getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tikv.node_profile.name").Raw(),
			tiflash_nodesize, actual_tiflash_nodesize,
			tikv_storage, getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tikv.node_profile.storage_gi").Raw(),
			tiflash_storage, actual_tiflash_storage)),
		allure.Action(func() {
			getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tidb.node_profile.name").String().Equal(tidb_nodesize)
			getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tikv.node_profile.storage_gi").Equal(tikv_storage)
			getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tikv.node_profile.name").String().Equal(tikv_nodesize)
			if tifish_count != 0 {
				getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tiflash.node_profile.storage_gi").Equal(tiflash_storage)
				getClusterInfoResp.JSON().Path("$.cluster.cluster_components.tiflash.node_profile.name").String().Equal(tiflash_nodesize)
			}
		}))

}

func CheckDeleteCluster(t assert.TestingT, clusterId, projectId string, checknum bool) {
	var total float64
	if clusterId == "" {
		return
	}
	dbassRequestInfo = GetDbassRequestInfo(t)
	orgId := dbassRequestInfo.CommonEnv.OrgId
	if projectId == "" {
		projectId = dbassRequestInfo.CommonEnv.ProjectId
	}
	pathparam := map[string]string{"org_id": orgId, "project_id": projectId}
	clusterPathParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}

	if checknum {
		getClusterListResp := dbassRequestInfo.DbassRequest(t, "getClusterList", nil, pathparam, nil, nil)
		total = getClusterListResp.JSON().Path("$.total").Raw().(float64)
		l4g.Info("getClusterListResp total is: %d", total)

		if total == 0.0 {
			return
		}
	}

	//删除集群
	delClusterResp := dbassRequestInfo.DbassRequest(t, "delCluster", nil, clusterPathParam, nil, nil)
	l4g.Info("delClusterResp:%v", delClusterResp.JSON().Raw())
	if checknum {
		allure.Step(allure.Description(fmt.Sprintf("delete cluster, pathParam:%s, delClusterResp:%s", clusterPathParam, delClusterResp.JSON().Raw())),
			allure.Action(func() {
				delClusterResp.Status(StatusOK)
			}))
	}

	if delClusterResp.Raw().StatusCode == 200 {
		DeleteIdInMap(clusterId)
	}

	//查看集群的详细信息, 如果 total 为 1 时，删除集群后就不能取到 total 值了
	if checknum {
		getClusterListResp := dbassRequestInfo.DbassRequest(t, "getClusterList", nil, pathparam, nil, nil)
		allure.Step(allure.Description(fmt.Sprintf("check delete cluster result, ExpectClusterNum:%f, ActualClusterNum:%s",
			total-1, getClusterListResp.JSON().Path("$.total").Raw())),
			allure.Action(func() {
				getClusterListResp.JSON().Path("$.total").Equal(total - 1)
			}))
	}

}

func ScaleCluster(t assert.TestingT, provider, projectId, clusterId string, tidb_count, tikv_count, tifish_count int, isDevTier, isEksGke bool) (bool, string, string, string, map[string]float64) {
	var tikvStorage, tiflashStorage int
	var tidbProfileId, tikvProfileId, tiflashProfileId string
	if clusterId == "" {
		return false, "", "", "", nil
	}
	dbassRequestInfo = GetDbassRequestInfo(t)

	orgId := dbassRequestInfo.CommonEnv.OrgId
	if projectId == "" {
		projectId = dbassRequestInfo.CommonEnv.ProjectId
	}
	if dbassRequestInfo.CommonEnv.TiflashCpu == "" {
		tifish_count = 0
	}
	clusterPathParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}
	var region string
	if isDevTier {
		tikvStorage, tiflashStorage = DevTierTikvStorage, DevTierTiflashStorage
	} else if provider == "aws" {
		tikvStorage, tiflashStorage = AwsTikvStorage, AwsTiflashStorage
		region = dbassRequestInfo.CommonEnv.AwsRegion
	} else if provider == "gcp" {
		tikvStorage, tiflashStorage = GcpTikvStorage, GcpTiflashStorage
		region = dbassRequestInfo.CommonEnv.GcpRegion
	}
	if isDevTier {
		tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId = DevTierTikvStorage, DevTierTiflashStorage, DevTierTidbProfileId, DevTierTikvProfileId, DevTierTiflashProfileId
	} else if provider == "aws" {
		if !isEksGke {
			tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId = AwsTikvStorage, AwsTiflashStorage, AwsTidbProfileId, AwsTikvProfileId, AwsTiflashProfileId
		} else {
			tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId = AwsTikvStorage, AwsTiflashStorage, AwsScaleTidbProfileId, AwsScaleTikvProfileId, AwsScaleTiflashProfileId
		}

	} else if provider == "gcp" {
		if !isEksGke {
			tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId = GcpTikvStorage, GcpTiflashStorage, GcpTidbProfileId, GcpTikvProfileId, GcpTiflashProfileId
		} else {
			tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId = GcpTikvStorage, GcpTiflashStorage, GcpScaleTidbProfileId, GcpScaleTikvProfileId, GcpScaleTiflashProfileId
		}
	}

	//扩容
	l4g.Info("begin to scale cluster!")
	var scale *Scale
	scale_cluster_price := make(map[string]float64)

	if tifish_count != 0 {
		scale = NewScale(tidb_count, tikv_count, tifish_count, tikvStorage+10, tiflashStorage+10, tidbProfileId, tikvProfileId, tiflashProfileId)
		scale_cluster_price["price"], scale_cluster_price["compute_price"], scale_cluster_price["storage_price"] = Get3Price(t, provider, region, tidb_count, tikv_count, tifish_count, tikvStorage+10, tiflashStorage+10, tidbProfileId, tikvProfileId, tiflashProfileId, isDevTier)
	} else {
		scale = NewScale(tidb_count, tikv_count, tifish_count, tikvStorage+10, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId)
		scale_cluster_price["price"], scale_cluster_price["compute_price"], scale_cluster_price["storage_price"] = Get3Price(t, provider, region, tidb_count, tikv_count, tifish_count, tikvStorage+10, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId, isDevTier)
	}
	scaleResp := dbassRequestInfo.DbassRequest(t, "scale", scale, clusterPathParam, nil, nil)
	l4g.Info("do the scale, body is: %+v, pathParam is: %s, scaleResp is %s", scale, clusterPathParam, scaleResp.JSON().Raw())
	allure.Step(allure.Description(fmt.Sprintf("do scale, body is: %+v, pathParam is: %s, scaleResp:%s", scale, clusterPathParam, scaleResp.JSON().Raw())),
		allure.Action(func() {
			scaleResp.JSON().Path("$.base_resp.err_code").String().Equal("0")
		}))

	if scaleResp.JSON().Path("$.base_resp.err_code").String().Raw() != "0" {
		return false, "", "", "", nil
	}

	CheckClusterInfoByDetail(t, clusterId, tifish_count, tikvStorage+10, tiflashStorage+10, tidbProfileId, tikvProfileId, tiflashProfileId, projectId)
	if provider == "aws" {
		AwsTidbProfileId, AwsTikvProfileId, AwsTiflashProfileId = tidbProfileId, tikvProfileId, tiflashProfileId
	} else {
		GcpTidbProfileId, GcpTikvProfileId, GcpTiflashProfileId = tidbProfileId, tikvProfileId, tiflashProfileId
	}

	return true, tidbProfileId, tikvProfileId, tiflashProfileId, scale_cluster_price
}

func UpdatePassword(t assert.TestingT, projectId, clusterId, password string) {
	//加载配置
	dbassRequestInfo = GetDbassRequestInfo(t)
	orgId := dbassRequestInfo.CommonEnv.OrgId
	pathParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}

	//更新password
	//body := map[string]string{"password": password, "verify_code": code}
	var updatePasswordResp *httpexpect.Response
	var body map[string]string
	for round := 0; round < 3; round++ {
		body = map[string]string{"password": password}
		updatePasswordResp = dbassRequestInfo.DbassRequest(t, "updatePassword", body, pathParam, nil, nil)
		l4g.Info("update password , the body is %s, pathParam is %s, updatePasswordResp is %+v", body,
			pathParam, updatePasswordResp.JSON().Raw())
		if updatePasswordResp.Status(StatusOK).JSON().Path("$.base_resp.err_code").String().Raw() == "0" {
			break
		}
		util.SecondTimeWait(6, 10, "Wait For Password Update")
	}

	allure.Step(allure.Description(fmt.Sprintf("update password code, body:%v, pathParam:%s, updatePasswordResp:%s", body, pathParam, updatePasswordResp.JSON().Raw())),
		allure.Action(func() {
			updatePasswordResp.Status(StatusOK).JSON().Path("$.base_resp.err_code").String().Equal("0")
		}))
	util.SecondTimeWait(6, 10, "Wait For Password Take Effect")
}
