package common

import (
	"fmt"
	"strconv"
	"time"

	l4g "github.com/alecthomas/log4go"
	"github.com/shopspring/decimal"

	"github.com/tidbcloud/qa-PlatformAPIAuto/models"
)

const StatusOK = 200
const Status400 = 400
const Status500 = 500

var dbassRequestInfo *DbassRequestInfo

// var createTable = "GcpVpcOperationCREATE TABLE IF NOT EXISTS testUser(id int(10) primary key,name varchar(20));"
var currentTime = time.Now().Unix()

var AwsTikvStorage, AwsTiflashStorage, GcpTikvStorage, GcpTiflashStorage, DevTierTikvStorage, DevTierTiflashStorage int
var AwsTidbProfileId, AwsTikvProfileId, AwsTiflashProfileId, GcpTidbProfileId, GcpTikvProfileId, GcpTiflashProfileId, DevTierTidbProfileId, DevTierTikvProfileId, DevTierTiflashProfileId string
var AwsScaleTidbProfileId, AwsScaleTikvProfileId, AwsScaleTiflashProfileId, GcpScaleTidbProfileId, GcpScaleTikvProfileId, GcpScaleTiflashProfileId string
var DeleteClusterIdList []map[string]string
var isarm int

var TiDBType = "COMPONENT_TYPE_TIDB"
var TiKVType = "COMPONENT_TYPE_TIKV"
var TiFlashType = "COMPONENT_TYPE_TIFLASH"

const (
	RestoreModeSnapshot RestoreMode = 1
	RestoreModePiTR     RestoreMode = 2
)

type RestoreMode int32

type CreateClus struct {
	OrgId    string `json:"org_id"`
	Provider string `json:"provider"`
	Name     string `json:"name"`
	//Password                 string          `json:"root_password"`
	Region                   string          `json:"region"`
	Components               []ComponentData `json:"components"`
	IsserverlessTier         bool            `json:"is_dev_tier"`
	PrimaryClusterId         string          `json:"primary_cluster_id,omitempty"`
	Port                     int             `json:"port,omitempty"`
	CrossAccountDeploymentId string          `json:"cross_account_deployment_id,omitempty"`
	SpendLimits              int             `json:"spend_limit,omitempty"`
}

type ComponentData struct {
	ComponentType   string `json:"component_type"`
	NodeProfileName string `json:"node_profile_name"`
	Replicas        int    `json:"replicas"`
	StorageSizeGi   int    `json:"storage_size_gi"`
}

func NewComponentData(componentType, nodeProfileId string, replicas, storageSizeGi int) ComponentData {
	return ComponentData{componentType, nodeProfileId, replicas, storageSizeGi}
}

func NewCreateClusterInfo(orgId, provider, name, region string, is_dev_tier bool,
	tidbCount, tikvCount, tiflashCount, tikvStorage, tiflashStorage int, tidbProfileId,
	tikvProfileId, tiflashProfileId, primaryClusterId, port, crossAccountDeploymentId string, spendLimits int) *CreateClus {
	if is_dev_tier {
		tiflashCount = 1
	}
	tidbComponentType := NewComponentData(TiDBType, tidbProfileId, tidbCount, 0)
	tikvComponentType := NewComponentData(TiKVType, tikvProfileId, tikvCount, tikvStorage)
	tiflashComponentType := NewComponentData(TiFlashType, tiflashProfileId, tiflashCount, tiflashStorage)

	var components []ComponentData
	if tiflashCount != 0 {
		components = []ComponentData{tidbComponentType, tikvComponentType, tiflashComponentType}
	} else {
		components = []ComponentData{tidbComponentType, tikvComponentType}
	}

	//后端的 port 字段为 int 型
	port_int, _ := strconv.Atoi(port)
	if is_dev_tier == false {
		return &CreateClus{orgId, provider, name, region,
			components, is_dev_tier, primaryClusterId, port_int, crossAccountDeploymentId, 0}
	} else {
		return &CreateClus{orgId, provider, name, region,
			components, is_dev_tier, primaryClusterId, 0, crossAccountDeploymentId, spendLimits}
	}
}

type CloudProvidersResponse struct {
	Resp            BaseResp         `json:"base_resp"`
	Cloud_Providers []Cloud_Provider `json:"cloud_providers"`
}

type Cloud_Provider struct {
	Name    string   `json:"name"`
	Regions []Region `json:"regions"`
}

type RegionCIDRConfiguration struct {
	CIDR         string     `json:"cidr"`
	Region       RegionInfo `json:"region"`
	ValidateOnly bool       `json:"validate_only"`
}

type RegionInfo struct {
	Name     string `json:"name"`
	Provider string `json:"provider"`
}

type Region struct {
	Area                     string `json:"area"`
	CountryCode              string `json:"country_code"`
	CrossAccountDeploymentId string `json:"cross_account_deployment_id"`
	DisplayName              string `json:"display_name"`
	Name                     string `json:"name"`
}
type UpdateClusName struct {
	ClusterName string `json:"cluster_name"`
}

func NewUpdateClusName(ClusterName string) *UpdateClusName {
	return &UpdateClusName{ClusterName}
}

type ManualBackup struct {
	Name       string `json:"name"`
	BackupType string `json:"backup_type"`
}

func NewManualBackup(name string) *ManualBackup {
	return &ManualBackup{name, "MANUAL"}
}

type AutoBackup struct {
	BackupTime      string `json:"backup_time"`
	BackupType      string `json:"backup_type"`
	MaxBackups      int    `json:"max_backups"`
	BackupMode      string `json:"backup_mode"`
	RetentionPeriod int    `json:"retention_period"`
}

func NewAutoBackup(backupTime string, maxBackup int) *AutoBackup {
	return &AutoBackup{backupTime, "AUTO", maxBackup, "FULL", 10}
}

type BackupSetting struct {
	BackupSchedule    CommonBackup `json:"backup_schedule"`
	Description       string       `json:"description"`
	ClusterId         string       `json:"cluster_id"`
	Pitr              PitrBackup   `json:"pitr"`
	Provider          string       `json:"provider"`
	Regions           []string     `json:"regions"`
	Volume            VolumeBackup `json:"volume_backup"`
	SwitchImmediately bool         `json:"switch_immediately"`
}

type CommonBackup struct {
	Disable         bool     `json:"disable"`
	BackupCycle     string   `json:"backup_cycle"`
	BackupTime      string   `json:"backup_time"`
	RetentionPeriod int      `json:"retention_period"`
	Weekdays        []string `json:"weekdays"`
}

type PitrBackup struct {
	Enable bool `json:"enable"`
}

type VolumeBackup struct {
	Enable bool `json:"enable"`
}

func NewBackupSetting(provider, clusterId, clusterRegion, dual_region string, commonBackupFlag, pitrBackupFlag,
	volumeBackupFlag bool, backTime string, retention int) *BackupSetting {
	var regionList []string
	weekdays := []string{"SUNDAY"}
	commonBackup := CommonBackup{commonBackupFlag, "DAILY", backTime, retention, weekdays}
	l4g.Info("commonBackup:%v", commonBackup)
	pitrBackup := PitrBackup{pitrBackupFlag}
	l4g.Info("pitrBackupFlag:%v", pitrBackupFlag)
	volumeBackup := VolumeBackup{volumeBackupFlag}
	l4g.Info("volumeBackup:%v", volumeBackupFlag)
	regionList = append(regionList, clusterRegion)
	if dual_region != "" {
		regionList = append(regionList, dual_region)
	}
	l4g.Info("regionList:%v", regionList)

	return &BackupSetting{commonBackup, "", clusterId, pitrBackup,
		provider, regionList, volumeBackup, false}
}

type UpgradeBackupSetting struct {
	SnapshotBackupSchedule   SnapshotBackup `json:"snapshot_backup_schedule"`
	DryRun                   bool           `json:"dry_run"`
	ContinuousBackupSchedule PitrBackup     `json:"continuous_backup_schedule"`
	Regions                  []BackupRegion `json:"regions"`
}

type SnapshotBackup struct {
	ScheduleType      string         `json:"schedule_type"`
	Disable           bool           `json:"disable"`
	RetentionPolicy   Retention      `json:"retention_policy"`
	DailyScheduleTime string         `json:"daily_schedule_time,omitempty"`
	Weeklyschedule    Weeklyschedule `json:"weekly_schedule,omitempty"`
}

type Retention struct {
	RetentionPeriod string `json:"retention_period"`
}

type Weeklyschedule struct {
	Days         []string `json:"days"`
	ScheduleTime string   `json:"schedule_time"`
}

type BackupRegion struct {
	DisplayName string `json:"display_name"`
	Name        string `json:"name"`
}

func NewUpgradeBackupSetting(clusterRegion, dual_region string, commonBackupFlag, pitrBackupFlag bool,
	retention, weeklyScheduleTime, dailyScheduleTime string) *UpgradeBackupSetting {
	var regionList []BackupRegion
	var snapshotBackup SnapshotBackup
	region1 := BackupRegion{clusterRegion, clusterRegion}
	regionList = append(regionList, region1)
	if dual_region != "" {
		region2 := BackupRegion{dual_region, dual_region}
		regionList = append(regionList, region2)
	}
	retentionPeriod := Retention{retention}
	weeklyschedule := Weeklyschedule{[]string{"SUNDAY"}, weeklyScheduleTime}
	if weeklyScheduleTime != "" {
		snapshotBackup = SnapshotBackup{"Weekly", commonBackupFlag,
			retentionPeriod, "", weeklyschedule}
	} else {

		snapshotBackup = SnapshotBackup{"Daily", commonBackupFlag,
			retentionPeriod, dailyScheduleTime, weeklyschedule}
	}
	pitrBackup := PitrBackup{pitrBackupFlag}

	return &UpgradeBackupSetting{snapshotBackup, false, pitrBackup, regionList}
}

type DualRegionBackup struct {
	Regions     []string `json:"regions"`
	Description string   `json:"description"`
}

func NewDualRegionBackup(region []string, description string) *DualRegionBackup {
	return &DualRegionBackup{region, description}
}

type RestoreBackup struct {
	ClusterName string          `json:"cluster_name"`
	Component   []ComponentData `json:"components"`
	Port        int             `json:"port"`
	//Password    string          `json:"password,omitempty"`
	RestoreMode  RestoreMode `json:"restore_mode"`
	RestoredTS   int64       `json:"restored_ts"`
	Region       string      `json:"region"`
	BackupRegion string      `json:"backup_region,omitempty"`
}

func NewRestoreBackup(isDevTier bool, clusterName string, port string, restoreMode RestoreMode, restoredTS int64,
	region string, tidbCount, tikvCount, tiflashCount, tikvStorage, tiflashStorage int, tidbProfileId, tikvProfileId,
	tiflashProfileId string, backupRegion string) *RestoreBackup {
	portInt, _ := strconv.Atoi(port)
	if isDevTier {
		portInt = 0
	}
	if dbassRequestInfo.CommonEnv.TiflashCpu == "" && !isDevTier {
		tiflashCount = 0
	}
	tidbComponentType := NewComponentData(TiDBType, tidbProfileId, tidbCount, 0)
	tikvComponentType := NewComponentData(TiKVType, tikvProfileId, tikvCount, tikvStorage)
	tiflashComponentType := NewComponentData(TiFlashType, tiflashProfileId, tiflashCount, tiflashStorage)

	var components []ComponentData
	if tiflashCount != 0 {
		components = []ComponentData{tidbComponentType, tikvComponentType, tiflashComponentType}
	} else {
		components = []ComponentData{tidbComponentType, tikvComponentType}
	}

	return &RestoreBackup{
		ClusterName:  clusterName,
		Component:    components,
		Port:         portInt,
		RestoreMode:  restoreMode,
		RestoredTS:   restoredTS,
		Region:       region,
		BackupRegion: backupRegion,
	}
}

type ServerlessRestoreBackup struct {
	RestoreMode string `json:"restore_mode"`
	RestoreTS   string `json:"restored_ts,omitempty"`
}

type Scale struct {
	Components []ComponentData `json:"components"`
}

func NewScale(tidbCount, tikvCount, tiflashCount, tikvStorage, tiflashStorage int, tidbProfileId, tikvProfileId, tiflashProfileId string) *Scale {
	var componentList []ComponentData
	componentList = append(componentList, NewComponentData(TiDBType, tidbProfileId, tidbCount, 0))
	componentList = append(componentList, NewComponentData(TiKVType, tikvProfileId, tikvCount, tikvStorage))
	componentList = append(componentList, NewComponentData(TiFlashType, tiflashProfileId, tiflashCount, tiflashStorage))
	return &Scale{componentList}
}

type TrafficFilter struct {
	TrafficFilter *Filter `json:"traffic_filters"`
}

type Filter struct {
	Cidrs           []*Cidr `json:"cidrs"`
	DisablePublicLb bool    `json:"disable_public_lb"`
}

type Cidr struct {
	Cidr        string `json:"cidr"`
	Description string `json:"description"`
}

func NewCidr(cidr, description string) *Cidr {
	return &Cidr{cidr, description}
}

func NewFilter(cidrs []*Cidr, disablePublicLb bool) *Filter {
	return &Filter{cidrs, disablePublicLb}
}

func NewTrafficFilter(cidr, description string, disablePublicLb bool) *TrafficFilter {
	var cidrs []*Cidr
	cidrs = append(cidrs, NewCidr(cidr, description))
	filter := NewFilter(cidrs, disablePublicLb)
	return &TrafficFilter{filter}
}

type AWSVpc struct {
	TenantRegion    string `json:"tenant_region"`
	TenantVpcId     string `json:"tenant_vpc_id"`
	TenantAccountId string `json:"tenant_account_id"`
	TenantVpcCidr   string `json:"tenant_vpc_cidr"`
	Region          string `json:"region"`
}

func NewAWSVpc(tenantRegion, tenantVpcId, tenantAccountId, tenantVpcCidr, region string) *AWSVpc {
	return &AWSVpc{tenantRegion, tenantVpcId,
		tenantAccountId, tenantVpcCidr, region}
}

type GCPVpc struct {
	TenantProjectId   string `json:"tenant_project_id"`
	TenantVpcRegion   string `json:"tenant_vpc_region"`
	RenantNetworkName string `json:"tenant_network_name"`
	Region            string `json:"region"`
	GcpVpcCidr        string `json:"tenant_vpc_cidr"`
}

func NewGCPVpc(tenantProjectId, tenantVpcRegion, renantNetworkName, region, gcpVpcCidr string) *GCPVpc {
	return &GCPVpc{tenantProjectId, tenantVpcRegion,
		renantNetworkName, region, gcpVpcCidr}
}

// old struct , doesn't use validate api
type BankCardInfo struct {
	Type       string `form:"payment_method_data[type]"`
	Email      string `form:"payment_method_data[billing_details][email]"`
	Phone      string `form:"payment_method_data[billing_details][phone]"`
	Name       string `form:"payment_method_data[billing_details][name]"`
	Line1      string `form:"payment_method_data[billing_details][address][line1]"`
	City       string `form:"payment_method_data[billing_details][address][city]"`
	Country    string `form:"payment_method_data[billing_details][address][country]"`
	PostalCode string `form:"payment_method_data[billing_details][address][postal_code]"`

	State    string `form:"payment_method_data[billing_details][address][state]"`
	Number   string `form:"payment_method_data[card][number]"`
	Cvc      string `form:"payment_method_data[card][cvc]"`
	ExpMonth string `form:"payment_method_data[card][exp_month]"`
	ExpYear  string `form:"payment_method_data[card][exp_year]"`
	Guid     string `form:"payment_method_data[guid]"`
	Muid     string `form:"payment_method_data[muid]"`
	Sid      string `form:"payment_method_data[sid]"`

	PastedFields              string `form:"payment_method_data[pasted_fields]"`
	PaymentUserAgent          string `form:"payment_method_data[payment_user_agent]"`
	TimeOnPage                string `form:"payment_method_data[time_on_page]"`
	Referrer                  string `form:"payment_method_data[referrer]"`
	ExpectedPaymentMethodType string `form:"expected_payment_method_type"`
	UseStripeSdk              string `form:"use_stripe_sdk"`
	WebauthnUvpaAvailable     string `form:"webauthn_uvpa_available"`
	SpcEligible               string `form:"spc_eligible"`
	Key                       string `form:"key"`
	ClientSecret              string `form:"client_secret"`
}

// old struct , doesn't use validate api
func NewBankCardInfo(number, client_secret string) *BankCardInfo {
	return &BankCardInfo{"card", "zhongmin@pingcap.com", "15608225", "test", "test",
		"test", "US", "100000", "test", number, "123", "03",
		"23", "ffc076db-2625-4130-a12b-a5c7a0e29ad1d38d9d", "5b761adb-a1b8-4023-b3f3-73ba0ea31169d96979",
		"65ba5cc1-513f-4b62-a525-8b1535f955cee0c83f", "number", "stripe.js/08e0cc1e0; stripe-js-v3/08e0cc1e0",
		"367261", "https://staging.tidbcloud.com/", "card", "true",
		"true", "false", "",
		client_secret}
}

// new struct , use validate api
type ValidateBankCardInfo struct {
	Type       string `form:"type"`
	Line1      string `form:"billing_details[address][line1]"`
	City       string `form:"billing_details[address][city]"`
	Country    string `form:"billing_details[address][country]"`
	PostalCode string `form:"billing_details[address][postal_code]"`
	State      string `form:"billing_details[address][state]"`
	Name       string `form:"billing_details[name]"`

	Number   string `form:"card[number]"`
	Cvc      string `form:"card[cvc]"`
	ExpMonth string `form:"card[exp_month]"`
	ExpYear  string `form:"card[exp_year]"`
	Guid     string `form:"guid"`
	Muid     string `form:"muid"`
	Sid      string `form:"sid"`

	PaymentUserAgent string `form:"payment_user_agent"`
	TimeOnPage       string `form:"time_on_page"`
	Key              string `form:"key"`
}

// new struct , use validate api
func NewValidateBankCardInfo(number string) *ValidateBankCardInfo {
	return &ValidateBankCardInfo{
		Type:             "card",
		Line1:            "test address",
		City:             "test city",
		Country:          "AX",
		PostalCode:       "100000",
		State:            "test ca",
		Name:             "test name",
		Number:           number,
		Cvc:              "123",
		ExpMonth:         "09",
		ExpYear:          "40",
		Guid:             "ffc076db-2625-4130-a12b-a5c7a0e29ad1d38d9d",
		Muid:             "5b761adb-a1b8-4023-b3f3-73ba0ea31169d96979",
		Sid:              "65ba5cc1-513f-4b62-a525-8b1535f955cee0c83f",
		PaymentUserAgent: "stripe.js/08e0cc1e0; stripe-js-v3/08e0cc1e0",
		TimeOnPage:       "367261",
		Key:              "",
	}
}

type EditBandCard struct {
	Id             string    `json:"id"`
	Card           *CardInfo `json:"card"`
	BillingDetails *Detail   `json:"billing_details"`
	Orgid          string    `json:"org_id"`
}

type CardInfo struct {
	Brand       string `json:"brand"`
	Country     string `json:"country"`
	ExpMonth    string `json:"exp_month"`
	ExpYear     string `json:"exp_year"`
	Fingerprint string `json:"fingerprint"`
	Funding     string `json:"funding"`
	Last4       string `json:"last4"`
}

func NewCardInfo(brand, fingerprint, last4 string) *CardInfo {
	return &CardInfo{brand, "US",
		"3", "2023", fingerprint, "credit", last4}
}

type Detail struct {
	Address *AddreeInfo `json:"address"`
	Email   string      `json:"email"`
	Name    string      `json:"name"`
	Phone   string      `json:"phone"`
}

func NewDetail(name string) *Detail {
	addressInfo := NewAddreeInfo()
	return &Detail{addressInfo, "zhongmin@pingcap.com", name, "15608225"}
}

type AddreeInfo struct {
	City       string `json:"city"`
	Country    string `json:"country"`
	Line1      string `json:"line1"`
	Line2      string `json:"line2"`
	PostalCode string `json:"postal_code"`
	State      string `json:"state"`
}

func NewAddreeInfo() *AddreeInfo {
	return &AddreeInfo{"test", "US", "test", "", "100000", "test"}
}

func NewEditBandCard(id, brand, fingerprint, last4, name, org_id string) *EditBandCard {
	cardInfo := NewCardInfo(brand, fingerprint, last4)
	detail := NewDetail(name)
	return &EditBandCard{id, cardInfo, detail, org_id}
}

type SetDefaultBankCard struct {
	DefaultSource string `json:"default_source"`
}

func NewSetDefaultBankCard(defaultSource string) *SetDefaultBankCard {
	return &SetDefaultBankCard{defaultSource}
}

type InviteUser struct {
	Email     string `json:"email"`
	RBAC_Role string `json:"rbac_role"`
}

func NewInviteUser(email, role string) *InviteUser {
	return &InviteUser{email, role}
}

type Auth0User struct {
	Password string `json:"password"`
	Token    string `json:"token"`
}

func NewAuth0User(password, token string) *Auth0User {
	return &Auth0User{password, token}
}

type Authenticate struct {
	ClientId        string `json:"client_id"`
	Username        string `json:"username"`
	Password        string `json:"password"`
	Realm           string `json:"realm"`
	Credential_type string `json:"credential_type"`
}

func NewAuthenticate(clientId, username, password string) *Authenticate {
	return &Authenticate{clientId, username, password,
		"custom-email", "http://auth0.com/oauth/grant-type/password-realm"}
}

type Authorize struct {
	ClientId     string `url:"client_id"`
	ResponseType string `url:"response_type"`
	RedirectUri  string `url:"redirect_uri"`
	Scope        string `url:"scope"`
	Realm        string `url:"realm"`
	State        string `url:"state"`
	Nonce        string `url:"nonce"`
	LoginTicket  string `url:"login_ticket"`
	Auth0Client  string `url:"auth0Client"`
}

func NewAuthorize(clientId, redirectUri,
	state, nonce, loginTicket, auth0Client string) *Authorize {
	return &Authorize{clientId, "token id_token", redirectUri,
		"openid email", "custom-email", state, nonce, loginTicket, auth0Client}
}

type Acception struct {
	FirstName string `json:"first_name"`
	LastName  string `json:"last_name"`
	Email     string `json:"email"`
	OrgId     string `json:"org_id"`
}

type SignUp struct {
	FirstName         string `json:"first_name"`
	LastName          string `json:"last_name"`
	Company           string `json:"company"`
	RecaptchaResponse string `json:"recaptcha_response"`
	Email             string `json:"email"`
	Password          string `json:"password"`
	AcceptService     bool   `json:"accept_service"`
	Job               string `json:"job"`
	Country           string `json:"country"`
	PhoneNumber       string `json:"phone_number"`
}

func NewSignUp(email, password string) *SignUp {
	return &SignUp{
		FirstName:         "QE AutoTest FirstName",
		LastName:          "QE AutoTest LastName",
		Company:           "QE AutoTest Org",
		RecaptchaResponse: "03AGdBq27bo33EsoWuKtxPx6t9JTHN5xASXtxqWyxXHV6LmUMw1qO5lUWLZtizIKrJ3_-N1v0_j0iMvU5hiZbmCu-b7RmsU9h4ZDOHn1JHEfA8oVLTDALGI3l3xrh_B8iz-B1gznlB_4NnuW4bGdcRCQGdzVC3gRqfWIf6_FAw9ELNOZSlYJVVGxjHk-LNrT4Tb7glOeqLFGuD0Hunorl72BIWFCAwOyw4p_Vf3yAQarg8DUDNzVyESoehIRzqnN3U1ZLFOzIeUYvq-z7gRB5iTn3Yym85xycVu32MMbP4ZXbI0ypdFn_-LqBmejcqodm4f7Z8bIk_hwM-IzcWuhJanWpIT_zL54j35f7767sGayG40WYWR0nBr8GpZkdAQdSLO1vuDPPUm93lj30Rla4TkLuCs0aks6-kBEl1iMSQPrP5floy9vP7NiJPb9y446ixRXFF9BWTSFtd",
		Email:             email,
		Password:          password,
		AcceptService:     true,
		Job:               "Data Architect",
		Country:           "CN",
		PhoneNumber:       "+86 13313313333"}
}
func NewAcception(email, org_id string) *Acception {
	return &Acception{"test", "test", email, org_id}
}

type ImportData struct {
	//ClusterId string `json:"cluster_id"`
	SourceUrl string `json:"source_url,omitempty"`
	//TargetUsername     string          `json:"target_username,omitempty"`
	//Filter             string          `json:"filter,omitempty"`
	//TargetPassword     string          `json:"target_password,omitempty"`
	DataSourceType int    `json:"data_source_type"`
	Region         string `json:"region"`
	DataFormat     int    `json:"data_format"`
	AwsRoleArn     string `json:"aws_role_arn,omitempty"`
	CsvFormat      *Csv   `json:"csv_format"`
	//CheckItems         []string         `json:"check_items,omitempty"`
	TargetTableInfos []TargetTableInfo `json:"target_table_infos,omitempty"`
	//ObjectNamePattern  string          `json:"object_name_pattern,omitempty"`
	//TargetTablePattern string          `json:"target_table_pattern,omitempty"`
	LocalImportCfg *LocalImportCfg `json:"local_import_cfg,omitempty"`
}

type TargetTableInfo struct {
	TargetTable TargetTable `json:"target_table"`
	CustomFile  string      `json:"custom_file,omitempty"`
	MatchedUri  string      `json:"matched_uri,omitempty"`
}

type TargetTable struct {
	Schema string `json:"schema"`
	Table  string `json:"table"`
}

type Csv struct {
	BackslashEscape   bool   `json:"backslash_escape"`
	Delimiter         string `json:"delimiter"`
	Header            bool   `json:"header"`
	NotNull           bool   `json:"not_null"`
	Null              string `json:"null"`
	Separator         string `json:"separator"`
	TrimLastSeparator bool   `json:"trim_last_separator"`
}

func NewImportData(sourceUrl,
	dbPassword, importRegion string, dataFormat, dataSourceType int, awsRoleArn, ObjectNamePattern, TargetTablePattern string, header bool, localImportCfg *LocalImportCfg) *ImportData {
	csv := &Csv{true, "\"", header, false, "\\N", ",", false}
	return &ImportData{sourceUrl, dataSourceType, importRegion, dataFormat, awsRoleArn, csv, nil, localImportCfg}
}

type Token struct {
	Auth0ClientSecret string `json:"auth0_client_secret"`
	Auth0ClientId     string `json:"auth0_client_id"`
	Auth0Domain       string `json:"auth0_domain"`
	Email             string `json:"email"`
}

func NewToken(auth0ClientSecret, auth0ClientId, auth0Domain, email string) *Token {
	return &Token{auth0ClientSecret, auth0ClientId, auth0Domain, email}
}

func NewTestConector(org_id, project_id, cluster_id, connector_type, url, user, password string, protocol *models.DataflowProtocol, dispatchType models.DataflowDispatchType, topic, topicPrefix, separator, topicSuffix, startTSO string) models.DataflowConnectorCreateReq {
	var connectorType models.DataflowConnectorType

	var (
		kafkaInfo models.DataflowKafkaInfo

		authentication       models.DataflowAuthentication
		broker               models.DataflowBroker
		dataFormat           models.DataflowDataFormat
		tableConfig          models.DataflowTableConfig
		tableMode            models.DataflowTableMode
		topicPartitionConfig models.DataflowTopicPartitionConfig
		mysqlInfo            models.DataflowMySQLInfo
		connection           models.DataflowConnection
		startPosition        models.DataflowStartPosition
		startMode            models.DataflowStartMode
		authType             models.DataflowKafkaAuthType

		brokerEndpoints = "54.212.135.87:9092"
		kafkaVersion    models.DataflowKafkaVersion
		compressionType models.DataflowCompressionType
		tLSEnable       = false

		bigintUnsignedHandlingMode *models.DataflowBigintUnsignedHandlingMode
		decimalHandlingMode        *models.DataflowDecimalHandlingMode
		enableTidbExtension        = false
		//protocol                   *models.DataflowProtocol
		schemaRegistry *models.DataflowSchemaRegistry

		defaultTopic = topic
		//dispatchType        models.DataflowDispatchType
		partitionDispatcher models.DataflowPartitionDispatcher
		partitionNum        int64
		replicationFactor   int64
	)
	if connector_type == "mysql" {
		connectorType = models.DataflowConnectorTypeMYSQL
		filterRule := make([]string, 0)
		filterRule = append(filterRule, "*.*")
		tableMode = models.DataflowTableModeFORCESYNC
		tableConfig = models.NewDataflowTableConfig(filterRule, &tableMode)
		l4g.Info("tableConfig:%+v,%v", tableConfig.FilterRule, *tableConfig.Mode)
		connection = models.NewDataflowConnection(url, password, user)
		l4g.Info("connection:%+v", connection)
		// set start mode as "FROM_NOW"

		startMode = models.DataflowStartModeFROMNOW
		startPosition = models.NewDataflowStartPosition(&startMode, "", "")
		l4g.Info("startPosition:%+v,%v,%v", *startPosition.Mode, startPosition.Tso, startPosition.Utc)
		mysqlInfo = models.NewDataflowMySQLInfo(&connection, &startPosition, &tableConfig)

	} else {
		connectorType = models.DataflowConnectorTypeKAFKA

		//authType disabled by default
		authType = models.DataflowKafkaAuthTypeDISABLE
		authentication = models.NewDataFlowAuthentication(&authType, "", "")
		l4g.Info("authType: %+v", authType)
		l4g.Info("authentication: %+v", authentication)
		compressionType = models.DataflowCompressionTypeNONE
		kafkaVersion = models.DataflowKafkaVersionKAFKAVERSION2XX
		broker = models.NewDataFlowBroker(brokerEndpoints, &compressionType, &kafkaVersion, tLSEnable)
		l4g.Info("brokerEndpoints: %+v", broker.BrokerEndpoints)
		l4g.Info("compressionType: %+v", broker.Compression)
		l4g.Info("KafkaVersion: %+v", broker.KafkaVersion)
		l4g.Info("TLSEnable: %v", broker.TLSEnable)

		//data format has many config and hierarchy. Only avro protocal need bigintUnsignedHandlingMode, using canal-json protocol by default
		//protocol = models.NewDataflowProtocol(models.DataflowProtocolCANALJSON)
		filterRule := make([]string, 0)
		filterRule = append(filterRule, "*.*")
		tableMode = models.DataflowTableModeFORCESYNC
		dataFormat = models.NewDataFlowDataFormat(bigintUnsignedHandlingMode, decimalHandlingMode, enableTidbExtension, protocol, schemaRegistry)
		l4g.Info("dataFormat:%+v", dataFormat)
		tableConfig = models.NewDataflowTableConfig(filterRule, &tableMode)
		l4g.Info("tableConfig:%+v,%v", tableConfig.FilterRule, *tableConfig.Mode)

		// dispatchType = models.DataflowDispatchTypeDISPATCHTYPEONETOPIC
		// partitionDispatcher = models.DataflowPartitionDispatcherINDEXVALUE
		partitionDispatcher = models.DataflowPartitionDispatcherTABLE
		partitionNum = 3
		replicationFactor = 1
		topicPartitionConfig = models.NewDataflowTopicPartitionConfig(defaultTopic, &dispatchType, &partitionDispatcher, partitionNum, replicationFactor, separator, topicPrefix, topicSuffix)
		l4g.Info("topicPartitionConfig.DefaultTopic: %+v", topicPartitionConfig.DefaultTopic)
		l4g.Info("topicPartitionConfig.DispatchType: %+v", topicPartitionConfig.DispatchType)
		l4g.Info("topicPartitionConfig.PartitionDispatcher: %+v", topicPartitionConfig.PartitionDispatcher)
		l4g.Info("topicPartitionConfig.PartitionNum: %v", topicPartitionConfig.PartitionNum)
		l4g.Info("topicPartitionConfig.replicationFactor: %v", topicPartitionConfig.ReplicationFactor)
		l4g.Info("topicPartitionConfig.topicPrefix: %v", topicPartitionConfig.TopicPrefix)
		l4g.Info("topicPartitionConfig.TopicSuffix: %v", topicPartitionConfig.TopicSuffix)
		l4g.Info("topicPartitionConfig.separator: %v", topicPartitionConfig.Separator)

		kafkaInfo = models.NewDataFlowKafkaInfo(&authentication, &broker, &dataFormat, &tableConfig, &topicPartitionConfig)
		l4g.Info("kafkaInfo.Authentication: %+v", *kafkaInfo.Authentication)
		l4g.Info("kafkaInfo.Broker: %+v", *kafkaInfo.Broker)
		l4g.Info("kafkaInfo.DataFormat: %+v", *kafkaInfo.DataFormat)
		l4g.Info("kafkaInfo.TableConfig: %+v", *kafkaInfo.TableConfig)
		l4g.Info("kafkaInfo.TopicPartitionConfig: %+v", *kafkaInfo.TopicPartitionConfig)

		//fmt.Printf("kafka info is: %+v, %+v, %+v, %+v, %+v, %+v, %+v, %+v, %+v, %+v, %+v \n", authentication, *authentication.AuthType, broker, broker.BrokerEndpoints, *broker.KafkaVersion, dataFormat, *dataFormat.Protocol, topicPartitionConfig, topicPartitionConfig.PartitionNum, *topicPartitionConfig.DispatchType, *topicPartitionConfig.PartitionDispatcher)

	}
	// central_connector_create_req - > dataflow_connector_create_req
	return models.DataflowConnectorCreateReq{
		ClusterID:              &cluster_id,
		ConnectorType:          &connectorType,
		IgnoreReplication:      true,
		KafkaInfo:              &kafkaInfo,
		MysqlInfo:              &mysqlInfo,
		OrgID:                  &org_id,
		Password:               password,
		ProjectID:              &project_id,
		StartTso:               startTSO,
		Topic:                  topic,
		URL:                    &url,
		User:                   user,
		ChangefeedInstanceType: "16rcu",
	}

}

type NodeProfilesRequest struct {
	IsDevTier bool   `json:"is_dev_tier"`
	OrgId     string `json:"org_id"`
	Provider  string `json:"provider"`
	Region    string `json:"region"`
}

func NewNodeProfilesRequest(isDevTier bool, orgId, provider, region string) *NodeProfilesRequest {
	return &NodeProfilesRequest{isDevTier, orgId, provider, region}
}

type NodeProfilesResponse struct {
	NodeProfiles []NodeProfile `json:"node_profiles"`
	Resp         BaseResp      `json:"base_resp"`
}

type NodeProfile struct {
	ComponentType string    `json:"component_type"`
	Profiles      []profile `json:"profiles"`
}

type profile struct {
	Id               string `json:"id"`
	Name             string `json:"name"`
	DefaultNodeNum   int    `json:"default_node_num"`
	MinStorageSizeGi int    `json:"min_storage_size_gi"`
	MaxStorageSizeGi int    `json:"max_storage_size_gi"`
	DisplayName      string `json:"display_name"`
	CPU              int    `json:"cpu_num"`
	Memory           int    `json:"memory_gi"`
}

type BaseResp struct {
	ErrCode string `json:"err_code"`
	ErrMsg  string `json:"err_msg"`
}

type ClusterFee struct {
	Components []ComponentData `json:"components"`
	IsDevTier  bool            `json:"is_dev_tier"`
	Provider   string          `json:"provider"`
	Region     string          `json:"region"`
}

func NewClusterFee(provider, region string, tidbCount, tikvCount, tiflashCount, tikvStorage, tiflashStorage int, tidbProfileId, tikvProfileId, tiflashProfileId string, isDevTier bool) *ClusterFee {
	var componentList []ComponentData
	if tidbCount != 0 {
		componentList = append(componentList, NewComponentData(TiDBType, tidbProfileId, tidbCount, 0))
	}
	if tikvCount != 0 {
		componentList = append(componentList, NewComponentData(TiKVType, tikvProfileId, tikvCount, tikvStorage))
	}
	if tiflashCount != 0 {
		componentList = append(componentList, NewComponentData(TiFlashType, tiflashProfileId, tiflashCount, tiflashStorage))
	}
	return &ClusterFee{componentList, isDevTier, provider, region}
}

type SetupIntent struct {
	PublicKey    string `json:"public_key"`
	ClientSecret string `json:"client_secret"`
}

// PaymentMethod is the response of payment method API
type StripePaymentMethod struct {
	ID             string          `json:"id"`
	Card           *Card           `json:"card"`
	BillingDetails *BillingDetails `json:"billing_details"`
}

// Card is the credit card
type Card struct {
	Brand       string `json:"brand"`
	Country     string `json:"country"`
	ExpMonth    uint64 `json:"exp_month,string"`
	ExpYear     uint64 `json:"exp_year,string"`
	Fingerprint string `json:"fingerprint"`
	Funding     string `json:"funding"`
	Last4       string `json:"last4"`
}

// BillingDetails is the user detail billing information
type BillingDetails struct {
	Address *Address `json:"address"`
	Email   *string  `json:"email"`
	Name    string   `json:"name"`
	Phone   *string  `json:"phone"`
}

// Address is the billing Address
type Address struct {
	City       string `json:"city"`
	Country    string `json:"country"`
	Line1      string `json:"line1"`
	Line2      string `json:"line2"`
	PostalCode string `json:"postal_code"`
	State      string `json:"state"`
}

type StripeCustomerInfo struct {
	ID            string   `json:"id"`
	TenantID      string   `json:"dbaas_id"`
	Email         string   `json:"email"`
	Name          string   `json:"name"`
	Description   string   `json:"description"`
	DefaultSource string   `json:"default_source"`
	Address       *Address `json:"address"`
}

type CostExplorerResult struct {
	BindedInvoiceCosts   Costs `json:"binded_invoice_costs"`
	UnbindedInvoiceCosts Costs `json:"unbind_invoice_costs"`
	CreditsCosts         Costs `json:"credits_costs"`
	InvoiceCosts         Costs `json:"invoice_costs"`
	TotalCosts           Costs `json:"total_costs"`
}

type Costs struct {
	CategoryCosts
	LabelsUnitsCosts map[string]LabelCosts `json:"label_unit_costs"`
}

type CategoryCosts struct {
	Price
	UnitsCosts         []UnitCosts      `json:"unit_costs,omitempty"`
	CategoryUnitsCosts map[string]Price `json:"category_unit_costs"`
}

type LabelCosts map[string]CategoryCosts

type Price struct {
	CostPrice string `json:"cost_price"`
	RawPrice  string `json:"raw_price"`
}

type UnitCosts struct {
	CostID        string            `json:"cost_id"`
	CostTimeStamp int64             `json:"cost_time_stamp"`
	Unit          string            `json:"unit"`
	Cost          int               `json:"cost"`
	Labels        map[string]string `json:"labels"`

	CostPrice       decimal.Decimal `json:"price"`
	RawPrice        decimal.Decimal `json:"raw_price"`
	PackageID       uint            `json:"package_id"`
	PackageVersion  uint            `json:"package_version"`
	BindedPackageID uint            `json:"binded_package_id"`
	ConsumedSource  string          `json:"consumed_source"`
	InvoiceID       int             `json:"invoice_id"`
	Discount        decimal.Decimal `json:"discount"`
	Internal        bool            `json:"internal"`
}

// audit log body struct
type AccessRecords struct {
	Org_id     string   `json:"org_id"`
	Project_id string   `json:"project_id"`
	Cluster_id string   `json:"cluster_id"`
	Record     *Records `json:"record"`
}
type Records struct {
	User_expr        string   `json:"user_expr"`
	Db_expr          string   `json:"db_expr"`
	Table_expr       string   `json:"table_expr"`
	Access_type_list []string `json:"access_type_list"`
}

func NewRecords(user_expr, db_expr, table_expr string, access_type_list []string) *Records {
	return &Records{user_expr, db_expr,
		table_expr, access_type_list}
}
func NewAccessRecords(org_id, project_id, cluster_id string, record *Records) *AccessRecords {
	return &AccessRecords{org_id, project_id,
		cluster_id, record}
}

type AuditLog struct {
	Org_id           string          `json:"org_id"`
	Project_id       string          `json:"project_id"`
	Cluster_id       string          `json:"cluster_id"`
	Enabled          bool            `json:"enabled"`
	Restart          bool            `json:"restart"`
	Audit_log_config *AuditLogConfig `json:"audit_log_config"`
}

type AuditLogConfig struct {
	Bucket_url       string `json:"bucket_url"`
	Role_arn         string `json:"role_arn"`
	Region           string `json:"region"`
	Data_source_type int    `json:"data_source_type"`
}

func NewAuditLog(org_id, project_id, cluster_id string, enabled, restart bool, audit_log_config *AuditLogConfig) *AuditLog {
	return &AuditLog{org_id, project_id, cluster_id,
		enabled, restart, audit_log_config}
}

func NewAuditLogConfig(bucket_url, role_arn, region string, data_source_type int) *AuditLogConfig {
	return &AuditLogConfig{bucket_url, role_arn, region,
		data_source_type}
}

type XAccountConfiguration struct {
	OrgId     string `json:"org_id"`
	ProjectId string `json:"project_id"`

	VpcId           string    `json:"vpc_id"`
	SecurityGroupId string    `json:"security_group_id"`
	SubnetIds       [3]string `json:"subnet_ids"`

	BucketName string `json:"bucket_name"`

	KmsKeyArn               string `json:"kms_key_arn"`
	PcaArnClusterComponents string `json:"pca_arn_cluster_components"`
	PcaArnClient            string `json:"pca_arn_client"`

	RoleArnEks       string `json:"role_arn_eks"`
	RoleArnNode      string `json:"role_arn_node"`
	RoleArnTidbCloud string `json:"role_arn_tidb_cloud"`

	Provider string `json:"provider"`
	Region   string `json:"region"`
}

func NewXAccountConfiguration(orgId, projectId, vpcId, securityGroupId, subnetId1, subnetId2, subnetId3, bucketName, kmsKeyArn, pcaArnClusterComponents, pcaArnClient, roleArnEks, roleArnNode, roleArnTidbCloud, provider, region string) *XAccountConfiguration {
	var subnetList [3]string = [3]string{subnetId1, subnetId2, subnetId3}
	return &XAccountConfiguration{orgId, projectId, vpcId, securityGroupId, subnetList, bucketName, kmsKeyArn, pcaArnClusterComponents, pcaArnClient, roleArnEks, roleArnNode, roleArnTidbCloud, provider, region}
}

type RestoreBackupWithComponents struct {
	Components  []ComponentData `json:"components"`
	Password    string          `json:"password"`
	ClusterName string          `json:"cluster_name"`
}

func NewRestoreBackupWithComponents(tidbCount, tikvCount, tiflashCount, tikvStorage, tiflashStorage int, tidbProfileId, tikvProfileId, tiflashProfileId, password, cluster_name string) *RestoreBackupWithComponents {
	var componentList []ComponentData
	if tidbCount != 0 {
		componentList = append(componentList, NewComponentData(TiDBType, tidbProfileId, tidbCount, 0))
	}
	if tikvCount != 0 {
		componentList = append(componentList, NewComponentData(TiKVType, tikvProfileId, tikvCount, tikvStorage))
	}
	if tiflashCount != 0 {
		componentList = append(componentList, NewComponentData(TiFlashType, tiflashProfileId, tiflashCount, tiflashStorage))
	}
	return &RestoreBackupWithComponents{componentList, password, cluster_name}
}

// billing credits 20231116 billing version
type Credits []CreditsPackage
type CreditsPackage struct {
	CreditsPackageID    uint              `json:"credits_package_id"`
	CreditsCode         string            `json:"credits_code"`
	TenantID            uint              `json:"tenant_id"`
	Status              string            `json:"status"`
	StartDate           string            `json:"start_date"`
	ClosedDate          string            `json:"closed_date"`
	ExpiredDate         string            `json:"expired_date"`
	BindedPackageID     *uint             `json:"binded_package_id"`
	RemainingCredits    decimal.Decimal   `json:"remaining_credits"`
	TotalCredits        decimal.Decimal   `json:"total_credits"`
	Type                string            `json:"type"`
	Usage               string            `json:"usage"`
	ClosedReason        string            `json:"closed_reason"`
	Note                string            `json:"note"`
	BindTypes           []*UnitFilterSlim `json:"bind_types"`
	UnitFilters         []*UnitFilterSlim `json:"unit_filters"`
	DiscountEnabled     bool              `json:"discount_enabled"`
	UnitFiltersInternal []*UnitFilter     `json:"-"`
	Internal            bool              `json:"internal"`
}

type UnitFilterSlim struct {
	FilterID    uint   `json:"filter_id"`
	TypeID      uint   `json:"type_id"` // this field is a deprecated
	Name        string `json:"name"`
	Description string `json:"description"`
	ParentID    uint   `json:"parent_id"`
	Internal    bool   `json:"-"`
	Priority    int    `json:"-"`
}

type UnitFilter struct {
	UnitFilterSlim
	General        bool              `json:"general"`
	Provider       string            `json:"provider"`
	Region         string            `json:"region"`
	Category       string            `json:"category"`
	Labels         map[string]string `json:"labels"`
	UnitKeyPattern string            `json:"unit_key_pattern"`
}

type CreditsSummary struct {
	TenantID                      uint            `json:"tenant_id"`
	TotalCredits                  decimal.Decimal `json:"total_credits"`
	TotalCostedCredits            decimal.Decimal `json:"total_costed_credits"`
	AvailableCredits              decimal.Decimal `json:"available_credits"`
	AvailableCostedCredits        decimal.Decimal `json:"available_costed_credits"`
	AvailableRemainingCredits     decimal.Decimal `json:"available_remaining_credits"`
	AvailablePOCCredits           decimal.Decimal `json:"available_poc_credits"`
	AvailableCostedPOCCredits     decimal.Decimal `json:"available_costed_poc_credits"`
	AvailableRemainingPOCCredits  decimal.Decimal `json:"available_remaining_poc_credits"`
	LastCreditsClosedDate         *time.Time      `json:"last_credits_closed_date"`
	ActiveCreditsPacakgesCount    uint            `json:"active_credits_packages_count"`
	ActivePOCCreditsPackagesCount uint            `json:"active_poc_credits_packages_count"`
}

type UnitFilterNode struct {
	UnitFilterSlim
	Children []*UnitFilterNode `json:"children"`
}

type AddDiscount struct {
	Value       decimal.Decimal   `json:"discount"`
	UnitFilters []*UnitFilterSlim `json:"unit_filters"`
	StartedAt   time.Time         `json:"started_at"`
	ExpiredAt   time.Time         `json:"expired_at"`
	Description string            `json:"description"`
	Usage       string            `json:"usage"`
}
type Invoice struct {
	Amount_due  string `json:"amount_due"`
	Amount_paid string `json:"amount_paid"`
	Created     string `json:"created"`
	Currency    string `json:"currency"`
	Due_date    string `json:"due_date"`
	Credit_used string `json:"credit_used"`
	Id          string `json:"id"`
	Number      string `json:"number"`
	Invoice_pdf string `json:"invoice_pdf"`
	Total       string `json:"total"`
	Paid        bool   `json:"paid"`
	Status      string `json:"status"`
}

type InvoiceList []Invoice

// bills details since release-v20221011 bills transparancy
type Bills_Detail struct {
	Amount        string `json:"amount"`
	Billable_cost string `json:"billable_cost"`
	Billed_date   string `json:"billed_date"`
	Cluster_name  string `json:"cluster_name"`
	Credit_usage  string `json:"credit_usage"`
	Project_name  string `json:"project_name"`
	Service       string `json:"service"`
}

type Bills_Details struct {
	Details []Bills_Detail `json:"details"`
}
type PrivatelinkService struct {
	CloudProvider string `json:"cloud_provider"`
}

func NewPrivatelinkService(cloudProvider string) *PrivatelinkService {
	return &PrivatelinkService{cloudProvider}
}

type PrivateLinkEndpoint struct {
	CloudProvider string `json:"cloud_provider,omitempty"`
	ClusterId     string `json:"cluster_id,omitempty"`
	ClusterName   string `json:"cluster_name,omitempty"`
	RegionName    string `json:"region_name,omitempty"`
	EndpointId    string `json:"endpoint_id,omitempty"`
	Status        string `json:"status,omitempty"`
	Message       string `json:"message,omitempty"`
	ServiceName   string `json:"service_name,omitempty"`
	ServiceStatus string `json:"service_status,omitempty"`
	ClusterStatus string `json:"cluster_status,omitempty"`
}

type CreatePrivateLinkEndpointReq struct {
	OrgId     string `json:"org_id,omitempty"`
	ProjectId string `json:"project_id,omitempty"`
	ClusterId string `json:"cluster_id,omitempty"`
	// Only PrivateLinkEndpoint.id is required
	PrivatelinkEndpoint *PrivateLinkEndpoint `json:"privatelink_endpoint,omitempty"`
}

type CreatePrivateLinkEndpointResp struct {
	PrivatelinkEndpoint *PrivateLinkEndpoint `json:"privatelink_endpoint,omitempty"`
	BaseResp            *BaseResp            `json:"base_resp,omitempty"`
}

type ListPrivateLinkEndpointsResp struct {
	Endpoints []*PrivateLinkEndpoint `json:"endpoints,omitempty"`
	BaseResp  *BaseResp              `json:"base_resp,omitempty"`
}

func NewPrivatelink(cloudProvider, id string) *PrivateLinkEndpoint {
	privatelinkEndPoint := &PrivateLinkEndpoint{cloudProvider, "", "", "", id, "", "", "", "", ""}
	return privatelinkEndPoint
	//return &CreatePrivateLinkEndpointReq{"", "", "", privatelinkEndPoint}
}

type Integration struct {
	OrgId         string   `json:"org_id"`
	ProjectId     string   `json:"project_id"`
	Type          string   `json:"type"`
	Payloads      []string `json:"payloads"`
	DatadogApiKey string   `json:"datadog_api_key"`
	DatadogSite   string   `json:"datadog_site"`
}

func NewDatadogIntegration(orgId, projectId, datadogApiKey string) *Integration {
	integration := &Integration{orgId, projectId, "INTEGRATION_TYPE_DATADOG", []string{"INTEGRATION_PAYLOAD_METRICS"}, datadogApiKey, "DATADOG_SITE_US1"}
	return integration
}

// contract management release-v20221018
type Contract struct {
	ContractType string `json:"contract_type"`
	ContractID   string `json:"contract_id"`
	ContactEmail string `json:"contact_email"`
	FilePath     string `json:"file_path"`
}

func NewContract(newType, newID, newEmail, newFile string) *Contract {
	newContract := &Contract{ContractType: newType, ContractID: newID, ContactEmail: newEmail, FilePath: newFile}
	return newContract
}

type DmData struct {
	ClusterPassword     string       `json:"cluster_password"`
	ClusterUser         string       `json:"cluster_user"`
	FullInstanceMigrate bool         `json:"full_instance_migrate"`
	Mode                string       `json:"mode"`
	Name                string       `json:"name"`
	PrecheckId          string       `json:"precheck_id,omitempty"`
	Sources             []SourceData `json:"sources"`
	SpecId              string       `json:"spec_id,omitempty"`
	ImportMode          string       `json:"import_mode,omitempty"`
}

func NewDmData(clusterPassword, clusterUser, mode, name, precheckId, specId, connProfileId string,
	fullInstanceMigrate bool, connProfileData ConnProfileData, importMode string) *DmData {
	var sources []SourceData
	var sourceData SourceData
	sourceData = NewSourceData(connProfileData, connProfileId)
	l4g.Info("sourceData:%v, connProfileId:%s", sourceData.GoString(), connProfileId)
	sources = append(sources, sourceData)
	return &DmData{clusterPassword, clusterUser, fullInstanceMigrate, mode,
		name, precheckId, sources, specId, importMode}
}

func (d DmData) GoString() string {
	return fmt.Sprintf("{\"cluster_password\":\"%s\", \"cluster_user\":\"%s\", \"full_instance_migrate\":\"%v\", \"mode\":\"%s\", \"name\":\"%s\", \"precheck_id\":\"%s\","+
		"\"sources\":\"%v\", \"spec_id\":\"%s\"", d.ClusterPassword, d.ClusterUser, d.FullInstanceMigrate, d.Mode, d.Name, d.PrecheckId,
		d.Sources, d.SpecId)
}

type DmScale struct {
	ToSpecId string `json:"to_spec_id"`
}

type SourceData struct {
	ConnProfile   ConnProfileData `json:"conn_profile"`
	ConnProfileId string          `json:"conn_profile_id,omitempty"`
}

func NewSourceData(connProfile ConnProfileData, connProfileId string) SourceData {
	return SourceData{connProfile, connProfileId}
}

func (d SourceData) GoString() string {
	return fmt.Sprintf("{\"conn_profile\":\"%s\", \"conn_profile_id\":\"%s\"}", d.ConnProfile.GoString(), d.ConnProfileId)
}

type ConnProfileData struct {
	ConnMethod string `json:"conn_method"`
	Host       string `json:"host"`
	Password   string `json:"password"`
	Port       int    `json:"port"`
	Region     string `json:"region"`
	Type       string `json:"type"`
	User       string `json:"user"`
	Name       string `json:"name"`
}

func NewConnProfileData(connMethod, host, password, region, typedata, user, name string, port int) ConnProfileData {
	return ConnProfileData{connMethod, host, password, port, region, typedata, user, name}
}

func (d ConnProfileData) GoString() string {
	return fmt.Sprintf("{\"conn_method\":\"%s\", \"host\":\"%s\", \"password\":\"%s\", \"port\":\"%d\", \"region\":\"%s\", \"type\":\"%s\", \"user\":\"%s\", \"name\":\"%s\"}", d.ConnMethod, d.Host, d.Password, d.Port, d.Region, d.Type,
		d.User, d.Name)
}

type UploadData struct {
	ContentLength string `json:"content_length"`
	FileName      string `json:"file_name"`
	Region        string `json:"region"`
}

func NewUploadData(contentLength, fileName, region string) *UploadData {
	newUploadData := &UploadData{contentLength, fileName, region}
	return newUploadData
}

type LocalCsvFormat struct {
	CsvFormat  *Csv   `json:"csv_format"`
	DataFormat string `json:"data_format"`
	FileName   string `json:"file_name"`
	N          string `json:"n"`
	Region     string `json:"region"`
}

func NewLocalCsvFormat(file_name, region string, header bool) *LocalCsvFormat {
	csv := &Csv{true, "\"", header, false, "\\N", ",", false}
	newLocalCsvFormat := &LocalCsvFormat{csv, "CSV", file_name, "5", region}
	return newLocalCsvFormat
}

type PreviewResp struct {
	Table *Table `json:"table"`
}

type Table struct {
	RowDataTypes []string      `json:"row_data_types"`
	RowHeaders   []string      `json:"row_headers"`
	RowValues    []interface{} `json:"row_values"`
}

type LocalImportCfg struct {
	Columns           []*ColumeInfo   `json:"columns"`
	FileName          string          `json:"file_name"`
	OriginalFile_name string          `json:"original_file_name"`
	TargetTable       *TargeTableInfo `json:"target_table"`
	Total_size        int             `json:"total_size"`
	PkColumns         []string        `json:"pk_columns"`
}

type ColumeInfo struct {
	ColumnName string `json:"column_name"`
	ColumnType string `json:"column_type"`
}

func NewColumeInfo(columnName, columnType string) *ColumeInfo {
	columeInfo := &ColumeInfo{columnName, columnType}
	return columeInfo
}

type TargeTableInfo struct {
	Schema string `json:"schema"`
	Table  string `json:"table"`
}

func NewLocalImportCfg(fileName, originalFile_name, schema, table string, columns []*ColumeInfo,
	totalSize int, pkColumns []string) *LocalImportCfg {
	targeTableInfo := &TargeTableInfo{schema, table}
	newLocalImportCfg := &LocalImportCfg{columns, fileName, originalFile_name,
		targeTableInfo, totalSize, pkColumns}

	return newLocalImportCfg
}

type ImportValidateInfo struct {
	AwsRoleArn     string   `json:"aws_role_arn"`
	CheckItems     []string `json:"check_items"`
	DataFormat     int      `json:"data_format"`
	DataSourceType int      `json:"data_source_type"`
	Region         string   `json:"region"`
	SourceUrl      string   `json:"source_url"`
}

type ImportInfo struct {
	AwsRoleArn     string `json:"aws_role_arn"`
	DataFormat     int    `json:"data_format"`
	DataSourceType int    `json:"data_source_type"`
	Filter         string `json:"filter"`
	Region         string `json:"region"`
	SourceUrl      string `json:"source_url"`
}

type CreateDataAPPBody struct {
	App_name    string   `json:"app_name"`
	App_type    string   `json:"app_type"`
	Cluster_ids []string `json:"cluster_ids"`
}

func NewCreateDataAPPBody(appName string, appType string, clusters []string) *CreateDataAPPBody {
	newCreateDataAPPBody := &CreateDataAPPBody{
		App_name:    appName,
		Cluster_ids: clusters,
		App_type:    appType,
	}
	return newCreateDataAPPBody
}

type CreateEndpointParam struct {
	Name         string           `json:"name,omitempty"`
	Description  string           `json:"description,omitempty"`
	Endpoint     string           `json:"endpoint,omitempty"`
	EndpointID   uint64           `json:"-,omitempty"`
	Method       string           `json:"method,omitempty"`
	ClusterIdStr string           `json:"cluster_id,omitempty"`
	Database     string           `json:"database,omitempty"`
	SqlTemplate  string           `json:"sql_template,omitempty"`
	Settings     EndpointSettings `json:"settings,omitempty"`
	Args         []EndpointArgs   `json:"args,omitempty"`
}

type EndpointFormat struct {
	ID          uint64           `json:"id,omitempty"`
	DataappId   uint64           `json:"dataappp_id,omitempty"`
	Name        string           `json:"name,omitempty"`
	Type        string           `json:"type,omitempty"`
	Description string           `json:"description,omitempty"`
	Endpoint    string           `json:"endpoint,omitempty"`
	Method      string           `json:"method,omitempty"`
	ClusterId   string           `json:"cluster_id,omitempty"`
	Database    string           `json:"database,omitempty"`
	SqlTemplate string           `json:"sql_template,omitempty"`
	Settings    EndpointSettings `json:"settings,omitempty"`
	Args        []EndpointArgs   `json:"args,omitempty"`
	CreatedBy   string           `json:"created_by,omitempty"`
	UpdatedBy   string           `json:"updated_by,omitempty"`
	// CreatedAt   utils.JsonTime   `json:"created_at"`
	// UpdatedAt   utils.JsonTime   `json:"updated_at"`
	ServiceUrl  string `json:"service_url,omitempty"`
	HasModified bool   `json:"has_modified,omitempty"`
}

type EndpointSettings struct {
	TimeOut   int `json:"timeout,omitempty"`
	RowsLimit int `json:"row_limit,omitempty"`
}

type EndpointArgs struct {
	Name        string            `json:"name,omitempty"`
	Type        string            `json:"type,omitempty"`       // string/bigint/bigint unsigned/double/array/enum/replace, if type is array/enum, should also specify the value-type.
	ValueType   string            `json:"value_type,omitempty"` // string/bigint/bigint unsigned/double, optional, the default is string.
	ValueMap    map[string]string `json:"value_map,omitempty"`  // enum/replace will use this map to verify enum value or replace.
	Required    int8              `json:"required,omitempty"`
	Default     string            `json:"default,omitempty"`
	Description string            `json:"description,omitempty"`
	Pattern     string            `json:"pattern,omitempty"` // regexp match pattern
}

type EndpointBodyArgs struct {
	Name  string `json:"name,omitempty"`
	Type  string `json:"type,omitempty"`
	Value string `json:"value,omitempty"`
}

type (
	DataAppType string
)
type DataApp struct {
	ID               uint64           `json:"id"`
	OrgId            string           `json:"org_id"`
	ProjectId        string           `json:"project_id"`
	ExternalAppID    string           `json:"external_app_id"`
	AppName          string           `json:"app_name"`
	AppType          DataAppType      `json:"app_type"`
	DeploymentRegion string           `json:"deployment_region"`
	CreatedBy        string           `json:"created_by"`
	UpdatedBy        string           `json:"updated_by"`
	IsDeleted        int8             `json:"is_deleted"`
	CreatedAt        string           `json:"created_at"`
	UpdatedAt        string           `json:"updated_at"`
	Endpoints        []EndpointFormat `json:"endpoints"`
	BaseUrl          string           `json:"base_url"`
}

type DataAPPResp struct {
	Code    uint64    `json:"code"`
	Message string    `json:"message"`
	Data    []DataApp `json:"data"`
}

type AutoGenerateEndpoint struct {
	ClusterId     string                     `json:"cluster_id"`
	Region        string                     `json:"region"`
	DB            string                     `json:"db"`
	Table         string                     `json:"table"`
	Operations    []string                   `json:"operations"`
	Configuration *AutoGenerateConfiguration `json:"configuration"`
}

type AutoGenerateConfiguration struct {
	IsDeploy bool   `json:"is_deploy"`
	TimeOut  int    `json:"timeout"`
	Tag      string `json:"tag"`
}

type APPClusters struct {
	BaseResp APPClustersBaseResp `json:"base_resp"`
	Data     []AppClusterInfo    `json:"data"`
}
type APPClustersBaseResp struct {
	ErrCode uint64 `json:"err_code"`
	ErrMsg  string `json:"err_msg"`
}

type AppClusterInfo struct {
	DataappID   uint64 `json:"dataapp_id"`
	ClusterID   string `json:"cluster_id"`
	ClusterName string `json:"cluster_name"`
	TierType    string `json:"tier_type"`
	Cloud       string `json:"cloud"`
	Region      string `json:"region"`
}

type OrgList struct {
	Orgs           []*Organization `json:"orgs,omitempty"`
	IsNewUser      bool            `json:"isNewUser,omitempty"`
	DefaultCluster string          `json:"defaultCluster,omitempty"`
}

type Organization struct {
	Id                        string `json:"id,omitempty"`
	Name                      string `json:"name,omitempty"`
	CreatedAt                 string `json:"created_at,omitempty"`
	Email                     string `json:"email,omitempty"`
	Country                   string `json:"country,omitempty"`
	Timezone                  int32  `json:"timezone,omitempty"`
	Status                    string `json:"status,omitempty"`
	Plan                      string `json:"plan,omitempty"`
	TotalCredit               string `json:"total_credit,omitempty"`
	RemainingCredit           string `json:"remaining_credit,omitempty"`
	HasDiscount               bool   `json:"has_discount,omitempty"`
	DiscountDescription       string `json:"discount_description,omitempty"`
	Discount                  string `json:"discount,omitempty"`
	ThirdPartyAccountProvider string `json:"third_party_account_provider,omitempty"`
	ThirdPartyAccountCode     string `json:"third_party_account_code,omitempty"`
	WhitelistFlag             uint32 `json:"whitelist_flag,omitempty"`
	ThirdPartyFreeTrial       bool   `json:"third_party_free_trial,omitempty"`
	OrgType                   string `json:"org_type,omitempty"`
	CompanyName               string `json:"company_name,omitempty"`
	UserSetTimezone           string `json:"user_set_timezone,omitempty"`
}

type TenantPlanInfo struct {
	TenantID          uint            `json:"tenant_id"`
	EffectivePlan     string          `json:"effective_plan"`
	DevTierPlanInfo   *PlanInfo       `json:"dev_tier_plan_info"`
	POCPlanInfo       *PlanInfo       `json:"poc_plan_info"`
	OnDemandPlanInfo  *PlanInfo       `json:"ondemand_plan_info"`
	EffectiveDiscount decimal.Decimal `json:"effective_discount"`
	POCCredits        decimal.Decimal `json:"poc_credits"`
}
type PlanInfo struct {
	Plan            string `json:"plan"`
	Status          string `json:"status"`
	StartedAt       string `json:"started_at"`
	ClosedAt        string `json:"closed_at"`
	BindedPackageID uint   `json:"-"`
	PlanID          uint   `json:"-"`
}

type PaymentMethod struct {
	TenantID        uint       `json:"tenant_id"`
	PaymentMethodID uint       `json:"payment_method_id"`
	PaymentType     string     `json:"payment_type"`
	PaymentCode     string     `json:"payment_code"`
	Payable         bool       `json:"payable"`
	ManagedBySales  bool       `json:"managed_by_sales"`
	PaymentSubCode  bool       `json:"payment_sub_code"`
	Status          string     `json:"status"`
	UnpayableAt     *time.Time `json:"unpayable_at"`
}

type OrgsInfo struct {
	Org            []OrgInfo `json:"orgs"`
	IsNewUser      bool      `json:"isNewUser"`
	DefaultCluster string    `json:"defaultCluster"`
}

type OrgInfo struct {
	Id                        string `json:"id"`
	Name                      bool   `json:"name"`
	CreatedAt                 string `json:"created_at"`
	Email                     string `json:"email"`
	Country                   string `json:"country"`
	Timezone                  int    `json:"timezone"`
	Status                    string `json:"status"`
	Plan                      string `json:"plan"`
	TotalCredit               bool   `json:"total_credit"`
	RemainingCredit           string `json:"remaining_credit"`
	HasDiscount               bool   `json:"has_discount"`
	DiscountDescription       string `json:"discount_description"`
	Discount                  int    `json:"discount"`
	ThirdPartyAccountProvider string `json:"third_party_account_provider"`
	ThirdPartyAccountCode     string `json:"third_party_account_code"`
	WhitelistFlag             int    `json:"whitelist_flag"`
	ThirdPartyFreeTrial       bool   `json:"third_party_free_trial"`
	OrgType                   string `json:"org_type"`
	CompanyName               string `json:"company_name"`
	UserSetTimezone           string `json:"user_set_timezone"`
}

type AddCredits struct {
	BindTypes       []BindType `json:"bind_types"`
	DiscountEnabled bool       `json:"discount_enabled"`
	ExpiredDate     string     `json:"expired_date"`
	StartDate       string     `json:"start_date"`
	TotalCredits    string     `json:"total_credits"`
	Usage           string     `json:"usage"`
}

type BindType struct {
	TypeId uint `json:"type_id"`
}

func NewAddCredits(startTime, endTime string) *AddCredits {
	bindType := BindType{1}
	addCredits := &AddCredits{[]BindType{bindType}, true, endTime,
		startTime, "1", "poc"}

	return addCredits
}

type SetPOCExpireTime struct {
	Action   string `json:"action"`
	RunTime  string `json:"run_time"`
	TenantId int    `json:"tenant_id"`
}

type Metrics struct {
	Status    string     `json:"status"`
	IsPartial bool       `json:"isPartial"`
	Data      MetricData `json:"data"`
}

type MetricData struct {
	ResultType string         `json:"resultType"`
	Result     []MetricDetail `json:"result"`
}

type MetricDetail struct {
	Metric interface{}     `json:"metric"`
	Values [][]interface{} `json:"result"`
}
