package br

import (
	"fmt"
	"time"

	l4g "github.com/alecthomas/log4go"
	"github.com/avast/retry-go"
	"github.com/dailymotion/allure-go"
	"github.com/tidbcloud/qa-PlatformAPIAuto/common"
	"github.com/tidbcloud/qa-PlatformAPIAuto/models"
	dpCommon "github.com/tidbcloud/qa-PlatformAPIAuto/webScene/common"
)

type CommonSceneTest struct {
	dpCommon.SceneTest

	MasterRegion    string
	SecondaryRegion string

	SnapshotRestoreClusterID string
	PitRestoreClusterID      string
}

func (s *CommonSceneTest) QueryDualRegionOption() {
	allure.Step(
		allure.Description("query dual region option"),
		allure.Action(func() {
			pathParam := map[string]string{
				"org_id":     s.DbaasRequestInfo.CommonEnv.OrgId,
				"project_id": s.DbaasRequestInfo.CommonEnv.ProjectId,
				"cluster_id": s.ClusterId,
			}
			err := retry.Do(
				func() error {
					callResp := s.DbaasRequestInfo.DbassRequest(s.T, "getBackupOptions", nil, pathParam, nil, nil)
					httpInfo := common.ParseHttpInfo(callResp)
					if httpInfo.RespStatusCode != common.StatusOK {
						return fmt.Errorf("status code is: %d, http details is: %s", httpInfo.RespStatusCode, httpInfo.ToString())
					}

					queryBackupOptionResp := &models.DataflowBackupOptionsResp{}
					httpInfo.UnmarshalRespBody(queryBackupOptionResp)

					if queryBackupOptionResp.ClusterID == nil {
						return fmt.Errorf("cluster id is empty, http details is: %s", httpInfo.ToString())
					}
					if queryBackupOptionResp.DualRegionOptions == nil ||
						queryBackupOptionResp.DualRegionOptions.ClusterRegion == nil ||
						len(queryBackupOptionResp.DualRegionOptions.RegionOptions) == 0 {
						return fmt.Errorf("dual region options is empty, http details is: %s", httpInfo.ToString())
					}
					s.MasterRegion = queryBackupOptionResp.DualRegionOptions.ClusterRegion.Name
					secondRegion, err := getBRSecondaryRegion(queryBackupOptionResp.DualRegionOptions.RegionOptions)
					if err != nil {
						return err
					}
					s.SecondaryRegion = secondRegion
					l4g.Info("master region is: %s, secondary region is: %s", s.MasterRegion, s.SecondaryRegion)
					return nil
				},
				retry.DelayType(retry.FixedDelay),
				retry.Delay(time.Second*10),
				retry.Attempts(6),
				retry.OnRetry(func(n uint, err error) {
					l4g.Info("#%d: %s\n", n, err)
				}),
			)
			if err != nil {
				l4g.Error(err)
				allure.FailNow(err)
			}
		}),
	)
}

func getBRSecondaryRegion(regionOptions []*models.BackupOptionsRespRegionOptions) (string, error) {
	// for aws regions:
	// regionOptions are regions deployed on 3-layers arch, and some regions may not be deployed on cloud-native arch.
	// To be compatible with cloud-native arch, we always use us-west-2 or us-east-1 as the secondary region,
	// because the two regions must be deployed both on 3-layer arch and cloud-native arch.
	for _, v := range regionOptions {
		if v.Region.Name == "us-west-2" || v.Region.Name == "us-east-1" {
			return v.Region.Name, nil
		}
	}

	// for non-aws regions:
	// use the first region as secondary region.
	return getNonOsakaAsSecondRegion(regionOptions)
}

// Osaka is a special region in AWS, we not support this region, but user requires backup to this region
// Therefore this region is not suitable for using testing the whole dual region br lifecycle
func getNonOsakaAsSecondRegion(regionOptions []*models.BackupOptionsRespRegionOptions) (string, error) {
	for _, v := range regionOptions {
		if v.Region.Name == "ap-northeast-3" {
			continue
		}
		return v.Region.Name, nil
	}
	return "", fmt.Errorf("can not find proper second region in %+v", regionOptions)
}

func (s *CommonSceneTest) OpenDualRegion() {
	allure.Step(
		allure.Description("open dual region"),
		allure.Action(func() {
			err := retry.Do(
				func() error {
					return s.modifyBackupSetting(func(req *dpCommon.ModifyBackupSettingReqV2) *dpCommon.ModifyBackupSettingReqV2 {
						req.Regions = []*dpCommon.RegionInfo{
							{
								Name: s.MasterRegion,
							},
							{
								Name: s.SecondaryRegion,
							},
						}
						return req
					})
				},
				retry.DelayType(retry.FixedDelay),
				retry.Delay(time.Second*10),
				retry.Attempts(6),
				retry.OnRetry(func(n uint, err error) {
					l4g.Info("#%d: %s\n", n, err)
				}),
			)

			if err != nil {
				l4g.Error(err)
				allure.FailNow(err)
			}
		}),
	)
}

func (s *CommonSceneTest) CloseDualRegion() {
	allure.Step(
		allure.Description("close dual region"),
		allure.Action(func() {
			err := retry.Do(
				func() error {
					if err := s.modifyBackupSetting(func(req *dpCommon.ModifyBackupSettingReqV2) *dpCommon.ModifyBackupSettingReqV2 {
						req.Regions = []*dpCommon.RegionInfo{
							{
								Name: s.MasterRegion,
							},
						}
						return req
					}); err != nil {
						return err
					}
					if err := s.createManualBackup(s.ClusterId + "-closeDR"); err != nil {
						return err
					}
					return nil
				},
				retry.DelayType(retry.FixedDelay),
				retry.Delay(time.Second*10),
				retry.Attempts(6),
				retry.OnRetry(func(n uint, err error) {
					l4g.Info("#%d: %s\n", n, err)
				}),
			)

			if err != nil {
				l4g.Error(err)
				allure.FailNow(err)
			}
		}),
	)
}

func (s *CommonSceneTest) WaitOpenDualRegionReady() {
	allure.Step(
		allure.Description("wait for opening dual region"),
		allure.Action(func() {
			err := retry.Do(
				func() error {
					backupSetting, err := s.queryBackupSetting()
					if err != nil {
						return err
					}

					if backupSetting.Status != dpCommon.BackupSettingStatus_Normal {
						return fmt.Errorf(
							"cluster %s backup setting status is: %s", s.ClusterId, backupSetting.Status)
					}
					return nil
				},
				retry.DelayType(retry.FixedDelay),
				retry.Delay(time.Second*10),
				retry.Attempts(6*60),
				retry.OnRetry(func(n uint, err error) {
					l4g.Info("#%d: %s\n", n, err)
				}),
			)

			if err != nil {
				l4g.Error(err)
				allure.FailNow(err)
			}
		}),
	)
}

func (s *CommonSceneTest) WaitCloseDualRegionReady() {
	allure.Step(
		allure.Description("wait for closing dual region"),
		allure.Action(func() {
			err := retry.Do(
				func() error {
					backupSetting, err := s.queryBackupSetting()
					if err != nil {
						return err
					}

					if backupSetting.Status != dpCommon.BackupSettingStatus_Normal {
						return fmt.Errorf("backup setting status is: %s", backupSetting.Status)
					}
					return nil
				},
				retry.DelayType(retry.FixedDelay),
				retry.Delay(time.Second*10),
				retry.Attempts(6*20),
				retry.OnRetry(func(n uint, err error) {
					l4g.Info("#%d: %s\n", n, err)
				}),
			)

			if err != nil {
				l4g.Error(err)
				allure.FailNow(err)
			}
		}),
	)
}

func (s *CommonSceneTest) OpenPiTR() {
	allure.Step(
		allure.Description("open pitr"),
		allure.Action(func() {
			err := retry.Do(
				func() error {
					if err := s.modifyBackupSetting(func(req *dpCommon.ModifyBackupSettingReqV2) *dpCommon.ModifyBackupSettingReqV2 {
						req.ContinuousBackupSchedule = &dpCommon.ContinuousBackupSchedule{
							Enable: true,
						}
						return req
					}); err != nil {
						return err
					}
					if err := s.createManualBackup(s.ClusterId + "-openPiTR"); err != nil {
						return err
					}
					return nil
				},
				retry.DelayType(retry.FixedDelay),
				retry.Delay(time.Second*10),
				retry.Attempts(6),
				retry.OnRetry(func(n uint, err error) {
					l4g.Info("#%d: %s\n", n, err)
				}),
			)

			if err != nil {
				l4g.Error(err)
				allure.FailNow(err)
			}
		}),
	)
}

func (s *CommonSceneTest) RestartPiTR() {
	allure.Step(
		allure.Description("restart pitr"),
		allure.Action(func() {
			err := retry.Do(
				func() error {
					if err := s.createManualBackup(s.ClusterId + "-restartPiTR"); err != nil {
						return err
					}
					return nil
				},
				retry.DelayType(retry.FixedDelay),
				retry.Delay(time.Second*10),
				retry.Attempts(6),
				retry.OnRetry(func(n uint, err error) {
					l4g.Info("#%d: %s\n", n, err)
				}),
			)

			if err != nil {
				l4g.Error(err)
				allure.FailNow(err)
			}
		}),
	)
}

func (s *CommonSceneTest) ExecuteSnapshotRestore() {
	allure.Step(
		allure.Description("execute snapshot restore"),
		allure.Action(func() {
			err := retry.Do(
				func() error {
					backup, err := s.queryLatestSuccesfulBackup()
					if err != nil {
						return err
					}
					pathParam := map[string]string{
						"org_id":     s.DbaasRequestInfo.CommonEnv.OrgId,
						"project_id": s.DbaasRequestInfo.CommonEnv.ProjectId,
						"cluster_id": s.ClusterId,
						"id":         *backup.ID,
					}
					executeRestoreReq := &dpCommon.ExecuteRestoreReq{
						Components: []*dpCommon.SimpleClusterComponent{
							{
								ComponentType:   dpCommon.ComponentType_COMPONENT_TYPE_TIDB,
								NodeProfileName: *backup.Cluster.ClusterComponents.Tidb.NodeProfile.Name,
								Replicas:        int32(*backup.Cluster.ClusterComponents.Tidb.Replicas),
							},
							{
								ComponentType:   dpCommon.ComponentType_COMPONENT_TYPE_TIKV,
								NodeProfileName: *backup.Cluster.ClusterComponents.Tikv.NodeProfile.Name,
								Replicas:        int32(*backup.Cluster.ClusterComponents.Tikv.Replicas),
								StorageSizeGi:   int32(*backup.Cluster.ClusterComponents.Tikv.NodeProfile.StorageGi),
							},
						},
						ClusterName:  s.ClusterId + "-snapshot-restore",
						Port:         4000,
						RestoreMode:  dpCommon.RestoreMode_RESTORE_MODE_SNAPSHOT,
						Region:       s.SecondaryRegion,
						BackupRegion: s.SecondaryRegion,
						Password:     s.DbaasRequestInfo.CommonEnv.DbPassword,
					}
					callResp := s.DbaasRequestInfo.DbassRequest(s.T, "restore", executeRestoreReq, pathParam, nil, nil)
					httpInfo := common.ParseHttpInfo(callResp, common.ReqBodyOp(executeRestoreReq))
					if httpInfo.RespStatusCode != common.StatusOK {
						return fmt.Errorf("status code is: %d, http details is: %s", httpInfo.RespStatusCode, httpInfo.ToString())
					}
					resp := &dpCommon.ExecuteRestoreResp{}
					httpInfo.UnmarshalRespBody(resp)
					if resp.ClusterId == "" {
						return fmt.Errorf("cluster id is empty, http details is: %s", httpInfo.ToString())
					}
					s.SnapshotRestoreClusterID = resp.ClusterId
					return nil
				},
				retry.DelayType(retry.FixedDelay),
				retry.Delay(time.Second*10),
				retry.Attempts(6),
				retry.OnRetry(func(n uint, err error) {
					l4g.Info("#%d: %s\n", n, err)
				}),
			)

			if err != nil {
				l4g.Error(err)
				allure.FailNow(err)
			}
		}),
	)
}

func (s *CommonSceneTest) WaitSnapshotRestoreReady() {
	allure.Step(
		allure.Description("waiting for executing snapshot restore"),
		allure.Action(func() {
			err := retry.Do(
				func() error {
					pathParam := map[string]string{
						"org_id":     s.DbaasRequestInfo.CommonEnv.OrgId,
						"project_id": s.DbaasRequestInfo.CommonEnv.ProjectId,
						"cluster_id": s.SnapshotRestoreClusterID,
					}
					callResp := s.DbaasRequestInfo.DbassRequest(s.T, "getClusterInfo", nil, pathParam, nil, nil)
					httpInfo := common.ParseHttpInfo(callResp)
					if httpInfo.RespStatusCode != common.StatusOK {
						return fmt.Errorf("status code is: %d, http details is: %s", httpInfo.RespStatusCode, httpInfo.ToString())
					}
					clusterResp := &models.CentralGetClusterResp{}
					httpInfo.UnmarshalRespBody(clusterResp)
					if err := ParseBaseRespError(clusterResp.BaseResp); err != nil {
						return err
					}
					if clusterResp.Cluster.Status != models.CentralClusterStatusNORMAL {
						return fmt.Errorf("cluster status is: %s", clusterResp.Cluster.Status)
					}
					return nil
				},
				retry.DelayType(retry.FixedDelay),
				retry.Delay(time.Second*10),
				retry.Attempts(6*60),
				retry.OnRetry(func(n uint, err error) {
					l4g.Info("#%d: %s\n", n, err)
				}),
			)
			if err != nil {
				l4g.Error(err)
				allure.FailNow(err)
			}
		}),
	)
}

func (s *CommonSceneTest) ExecutePiTRestore() {
	allure.Step(
		allure.Description("execute pit restore"),
		allure.Action(func() {
			err := retry.Do(
				func() error {
					pathParam := map[string]string{
						"org_id":     s.DbaasRequestInfo.CommonEnv.OrgId,
						"project_id": s.DbaasRequestInfo.CommonEnv.ProjectId,
						"cluster_id": s.ClusterId,
						"id":         "0",
					}
					restoreTs := time.Now().Add(-time.Minute * 5).Unix()
					executeRestoreReq := &dpCommon.ExecuteRestoreReq{
						Components: []*dpCommon.SimpleClusterComponent{
							{
								ComponentType:   dpCommon.ComponentType_COMPONENT_TYPE_TIDB,
								NodeProfileName: "4C16G",
								Replicas:        2,
							},
							{
								ComponentType:   dpCommon.ComponentType_COMPONENT_TYPE_TIKV,
								NodeProfileName: "4C16G",
								Replicas:        3,
								StorageSizeGi:   200,
							},
						},
						ClusterName:  s.ClusterId + "-pit-restore",
						Port:         4000,
						RestoreMode:  dpCommon.RestoreMode_RESTORE_MODE_PITR,
						RestoredTs:   restoreTs,
						Region:       s.SecondaryRegion,
						BackupRegion: s.SecondaryRegion,
						Password:     s.DbaasRequestInfo.CommonEnv.DbPassword,
					}
					callResp := s.DbaasRequestInfo.DbassRequest(s.T, "restore", executeRestoreReq, pathParam, nil, nil)
					httpInfo := common.ParseHttpInfo(callResp, common.ReqBodyOp(executeRestoreReq))
					if httpInfo.RespStatusCode != common.StatusOK {
						return fmt.Errorf("status code is: %d, http details is: %s", httpInfo.RespStatusCode, httpInfo.ToString())
					}
					resp := &dpCommon.ExecuteRestoreResp{}
					httpInfo.UnmarshalRespBody(resp)
					if resp.ClusterId == "" {
						return fmt.Errorf("cluster id is empty, http details is: %s", httpInfo.ToString())
					}
					s.PitRestoreClusterID = resp.ClusterId
					return nil
				},
				retry.DelayType(retry.FixedDelay),
				retry.Delay(time.Second*10),
				retry.Attempts(6),
				retry.OnRetry(func(n uint, err error) {
					l4g.Info("#%d: %s\n", n, err)
				}),
			)

			if err != nil {
				l4g.Error(err)
				allure.FailNow(err)
			}
		}),
	)
}

func (s *CommonSceneTest) WaitPitRestoreReady() {
	allure.Step(
		allure.Description("waiting for executing pit restore"),
		allure.Action(func() {
			err := retry.Do(
				func() error {
					pathParam := map[string]string{
						"org_id":     s.DbaasRequestInfo.CommonEnv.OrgId,
						"project_id": s.DbaasRequestInfo.CommonEnv.ProjectId,
						"cluster_id": s.PitRestoreClusterID,
					}
					callResp := s.DbaasRequestInfo.DbassRequest(s.T, "getClusterInfo", nil, pathParam, nil, nil)
					httpInfo := common.ParseHttpInfo(callResp)
					if httpInfo.RespStatusCode != common.StatusOK {
						return fmt.Errorf("status code is: %d, http details is: %s", httpInfo.RespStatusCode, httpInfo.ToString())
					}
					clusterResp := &models.CentralGetClusterResp{}
					httpInfo.UnmarshalRespBody(clusterResp)
					if err := ParseBaseRespError(clusterResp.BaseResp); err != nil {
						return err
					}
					if clusterResp.Cluster.Status != models.CentralClusterStatusNORMAL {
						return fmt.Errorf("cluster status is: %s", clusterResp.Cluster.Status)
					}
					return nil
				},
				retry.DelayType(retry.FixedDelay),
				retry.Delay(time.Second*10),
				retry.Attempts(6*60),
				retry.OnRetry(func(n uint, err error) {
					l4g.Info("#%d: %s\n", n, err)
				}),
			)
			if err != nil {
				l4g.Error(err)
				allure.FailNow(err)
			}
		}),
	)
}

func (s *CommonSceneTest) CleanupBackups() {
	allure.Step(
		allure.Description("cleanup backups"),
		allure.Action(func() {
			err := retry.Do(
				func() error {
					backups, err := s.listBackups("")
					if err != nil {
						return err
					}

					for _, item := range backups.Items {
						pathParam := map[string]string{
							"org_id":     s.DbaasRequestInfo.CommonEnv.OrgId,
							"project_id": s.DbaasRequestInfo.CommonEnv.ProjectId,
							"cluster_id": *item.Cluster.ClusterID,
							"id":         *item.ID,
						}
						callResp := s.DbaasRequestInfo.DbassRequest(s.T, "deleteBackup", nil, pathParam, nil, nil)
						httpInfo := common.ParseHttpInfo(callResp)
						if httpInfo.RespStatusCode != common.StatusOK {
							return fmt.Errorf("status code is: %d, http details is: %s", httpInfo.RespStatusCode, httpInfo.ToString())
						}
					}
					return nil
				},
				retry.DelayType(retry.FixedDelay),
				retry.Delay(time.Second*10),
				retry.Attempts(6),
				retry.OnRetry(func(n uint, err error) {
					l4g.Info("#%d: %s\n", n, err)
				}),
			)
			if err != nil {
				l4g.Error(err)
				allure.FailNow(err)
			}
		}),
	)
}

func (s *CommonSceneTest) queryLatestSuccesfulBackup() (*models.CentralBackup, error) {
	resp, err := s.listBackups(BackupStatusSuccess)
	if err != nil {
		return nil, err
	}
	if len(resp.Items) == 0 {
		return nil, fmt.Errorf("backup list is empty")
	}
	backup := resp.Items[0]
	return backup, nil
}

func (s *CommonSceneTest) listBackups(status BackupStatus) (*models.CentralBackups, error) {
	pathParam := map[string]string{
		"org_id":     s.DbaasRequestInfo.CommonEnv.OrgId,
		"project_id": s.DbaasRequestInfo.CommonEnv.ProjectId,
		"cluster_id": s.ClusterId,
	}
	queryParam := map[string]string{}
	if status != "" {
		queryParam["status"] = string(status)
	}

	callResp := s.DbaasRequestInfo.DbassRequest(s.T, "getBackupList", nil, pathParam, queryParam, nil)
	httpInfo := common.ParseHttpInfo(callResp)
	if httpInfo.RespStatusCode != common.StatusOK {
		return nil, fmt.Errorf("status code is: %d, http details is: %s", httpInfo.RespStatusCode, httpInfo.ToString())
	}

	resp := &models.CentralBackups{}
	httpInfo.UnmarshalRespBody(resp)
	return resp, nil
}

func (s *CommonSceneTest) ClosePiTR() {
	allure.Step(
		allure.Description("close pitr"),
		allure.Action(func() {
			err := retry.Do(
				func() error {
					return s.modifyBackupSetting(func(req *dpCommon.ModifyBackupSettingReqV2) *dpCommon.ModifyBackupSettingReqV2 {
						req.ContinuousBackupSchedule.Enable = false
						return req
					})
				},
				retry.DelayType(retry.FixedDelay),
				retry.Delay(time.Second*10),
				retry.Attempts(6),
				retry.OnRetry(func(n uint, err error) {
					l4g.Info("#%d: %s\n", n, err)
				}),
			)

			if err != nil {
				l4g.Error(err)
				allure.FailNow(err)
			}
		}),
	)
}

func (s *CommonSceneTest) WaitOpenPiTRReady() {
	allure.Step(
		allure.Description("wait for opening pitr"),
		allure.Action(func() {
			err := retry.Do(
				func() error {
					backupSetting, err := s.queryBackupSetting()
					if err != nil {
						return err
					}

					if backupSetting.Status != dpCommon.BackupSettingStatus_Normal {
						return fmt.Errorf("backup setting status is: %s", backupSetting.Status)
					}
					return nil
				},
				retry.DelayType(retry.FixedDelay),
				retry.Delay(time.Second*10),
				retry.Attempts(6*60),
				retry.OnRetry(func(n uint, err error) {
					l4g.Info("#%d: %s\n", n, err)
				}),
			)

			if err != nil {
				l4g.Error(err)
				allure.FailNow(err)
			}
		}),
	)
}

func (s *CommonSceneTest) WaitClosePiTRReady() {
	allure.Step(
		allure.Description("wait for closing pitr"),
		allure.Action(func() {
			err := retry.Do(
				func() error {
					backupSetting, err := s.queryBackupSetting()
					if err != nil {
						return err
					}

					if backupSetting.Status != dpCommon.BackupSettingStatus_Normal {
						return fmt.Errorf("backup setting status is: %s", backupSetting.Status)
					}
					return nil
				},
				retry.DelayType(retry.FixedDelay),
				retry.Delay(time.Second*10),
				retry.Attempts(6*10),
				retry.OnRetry(func(n uint, err error) {
					l4g.Info("#%d: %s\n", n, err)
				}),
			)

			if err != nil {
				l4g.Error(err)
				allure.FailNow(err)
			}
		}),
	)
}

type ModifyBackupSettingReqBuilder func(req *dpCommon.ModifyBackupSettingReqV2) *dpCommon.ModifyBackupSettingReqV2

func (s *CommonSceneTest) modifyBackupSetting(builders ...ModifyBackupSettingReqBuilder) error {
	queryBackupSettingResp, err := s.queryBackupSetting()
	if err != nil {
		return err
	}

	pathParam := map[string]string{
		"org_id":     s.DbaasRequestInfo.CommonEnv.OrgId,
		"project_id": s.DbaasRequestInfo.CommonEnv.ProjectId,
		"cluster_id": s.ClusterId,
	}
	modifyReq := &dpCommon.ModifyBackupSettingReqV2{
		Regions:                  queryBackupSettingResp.Regions,
		SnapshotBackupSchedule:   queryBackupSettingResp.SnapshotBackupSchedule,
		ContinuousBackupSchedule: queryBackupSettingResp.ContinuousBackupSchedule,
	}
	for _, builder := range builders {
		modifyReq = builder(modifyReq)
	}
	callResp := s.DbaasRequestInfo.DbassRequest(s.T, "modifyBackupSettingV2", modifyReq, pathParam, nil, nil)
	httpInfo := common.ParseHttpInfo(callResp, common.ReqBodyOp(modifyReq))
	if httpInfo.RespStatusCode != common.StatusOK {
		return fmt.Errorf("status code is: %d, http details is: %s", httpInfo.RespStatusCode, httpInfo.ToString())
	}
	return nil
}

func (s *CommonSceneTest) createManualBackup(name string) error {
	pathParam := map[string]string{
		"org_id":     s.DbaasRequestInfo.CommonEnv.OrgId,
		"project_id": s.DbaasRequestInfo.CommonEnv.ProjectId,
		"cluster_id": s.ClusterId,
	}
	createReq := &dpCommon.CreateBackupReq{
		BackupType: dpCommon.BackupType_MANUAL,
		Name:       name,
	}
	callResp := s.DbaasRequestInfo.DbassRequest(s.T, "manualBackup", createReq, pathParam, nil, nil)
	httpInfo := common.ParseHttpInfo(callResp, common.ReqBodyOp(createReq))
	if httpInfo.RespStatusCode != common.StatusOK {
		return fmt.Errorf("status code is: %d, http details is: %s", httpInfo.RespStatusCode, httpInfo.ToString())
	}
	return nil
}

func (s *CommonSceneTest) queryBackupSetting() (*dpCommon.QueryBackupSettingRespV2, error) {
	pathParam := map[string]string{
		"org_id":     s.DbaasRequestInfo.CommonEnv.OrgId,
		"project_id": s.DbaasRequestInfo.CommonEnv.ProjectId,
		"cluster_id": s.ClusterId,
	}
	callResp := s.DbaasRequestInfo.DbassRequest(s.T, "getBackupSettingV2", nil, pathParam, nil, nil)
	httpInfo := common.ParseHttpInfo(callResp)
	if httpInfo.RespStatusCode != common.StatusOK {
		return nil, fmt.Errorf("status code is: %d, http details is: %s", httpInfo.RespStatusCode, httpInfo.ToString())
	}

	queryBackupSettingResp := &dpCommon.QueryBackupSettingRespV2{}
	httpInfo.UnmarshalRespBody(queryBackupSettingResp)

	if queryBackupSettingResp.Status == "" {
		return nil, fmt.Errorf("status is empty, http details is: %s", httpInfo.ToString())
	}

	if queryBackupSettingResp.SnapshotBackupSchedule == nil ||
		queryBackupSettingResp.ContinuousBackupSchedule == nil ||
		len(queryBackupSettingResp.Regions) == 0 {
		return nil, fmt.Errorf("backup setting is empty, http details is: %s", httpInfo.ToString())
	}
	return queryBackupSettingResp, nil
}

func ParseBaseRespError(baseResp *models.CentralBaseResp) error {
	if baseResp == nil {
		return nil
	}
	if baseResp.ErrCode == "" || baseResp.ErrCode == "0" {
		return nil
	}
	return fmt.Errorf("error code is: %s, error message is: %s", baseResp.ErrCode, baseResp.ErrMsg)
}
