package config

import (
	"sync/atomic"

	"github.com/tidbcloud/metrics-server/central/db/entity"
	"github.com/tidbcloud/metrics-server/pkg/ratecontroller/types"
	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
)

var globalConf *CentralConfig = &CentralConfig{}
var topSQLTLSConf atomic.Value // stores TLSConfig for TopSQL TiDB storage

type CentralConfig struct {
	ServerConfig           ServerConfig           `mapstructure:"server"`
	GrpcConfig             GrpcConfig             `mapstructure:"grpc"`
	MysqlConfig            MysqlConfig            `mapstructure:"mysql"`
	Auth0Config            Auth0Config            `mapstructure:"auth0"`
	O11yGlobalServerConfig O11yGlobalServerConfig `mapstructure:"o11yGlobalServer"`

	/* ================ following fields no need to config ================ */

	InfraAPIConfig    InfraAPIConfig    `mapstructure:"infraAPI"`    // no need to config
	AwsConfig         AwsConfig         `mapstructure:"aws"`         // no need to config
	BillingConfig     BillingConfig     `mapstructure:"billing"`     // no need to config
	ProxyConfig       ProxyConfig       `mapstructure:"proxy"`       // no need to config
	InfraConfig       InfraConfig       `mapstructure:"infra"`       // no need to config
	ZendeskConfig     ZendeskConfig     `mapstructure:"zendesk"`     // no need to config
	MarketPlaceConfig MarketPlaceConfig `mapstructure:"marketPlace"` // no need to config

}

type GrpcConfig struct {
	CoreSvcAddr            string `mapstructure:"coreSvcAddr" default:"core-server-grpc:8888"`
	AccountProviderSvcAddr string `mapstructure:"accountProviderSvcAddr" default:"account-provider-grpc:10000"`
}

type MarketPlaceConfig struct {
	EnableBackground bool `mapstructure:"marketplaceBackground"`

	AWSProductCode      string `mapstructure:"awsProductCode" default:"true"`
	AWSRole             string `mapstructure:"awsRole"`
	AWSSQS              string `mapstructure:"awsSQS"`
	EnableAwsBackground bool   `mapstructure:"awsBackground"`

	GCPProductCode        string `mapstructure:"gcpProductCode"`
	GCPProject            string `mapstructure:"gcpProject"`
	GCPISSURL             string `mapstructure:"gcpISSURL" default:"https://www.googleapis.com/robot/v1/metadata/x509/cloud-commerce-partner@system.gserviceaccount.com"`
	GCPProcurementBaseUrl string `mapstructure:"gcpProcurementBaseUrl" default:"https://cloudcommerceprocurement.googleapis.com/"`
	GCPPubSubTopic        string `mapstructure:"gcpPubSubTopic"`
	GCPMarketPlaceSA      string `mapstructure:"gcpMarketplaceSA"`
	EnableGCPBackground   bool   `mapstructure:"gcpBackground"`
}

type HibernationConfig struct {
	DryRun                       bool  `mapstructure:"dryRun" default:"false"`
	IdleDurationThresholdMinutes int64 `mapstructure:"idleDurationThresholdMinutes" default:"60"`
	CheckIdleIntervalMinutes     int64 `mapstructure:"checkIdleIntervalMinutes" default:"5"`
}

type RateControlConfigItem struct {
	Scene *types.Scene  `mapstructure:"scene"`
	Rates []*types.Rate `mapstructure:"rates"`
}

type RateControlConfig struct {
	InviteUser               RateControlConfigItem `mapstructure:"inviteUser"`
	RegistrationVerification RateControlConfigItem `mapstructure:"registrationVerification"`
	SendPasswordVerifyCode   RateControlConfigItem `mapstructure:"sendPasswordVerifyCode"`
}

type ServerConfig struct {
	// Log level: debug, info, warn, error, fatal
	LogLevel         string `mapstructure:"logLevel" default:"info" validate:"oneof=debug info warn error fatal"`
	EnableDBQueryLog bool   `mapstructure:"enableDBQueryLog" default:"false"`
	Stage            string `mapstructure:"stage" validate:"required"`
	// central server cidr
	GrpcPort int `mapstructure:"grpcPort" default:"10000"`
	// user alerts webhook port in metrics-api
	AlertsListenAddr string `mapstructure:"alertsListenAddr" default:"0.0.0.0:8081"`
	// the central metrics port
	MetricsPort uint16 `mapstructure:"metricsPort" default:"9090"`
	// listen addr for metrics-server self
	MetricsListenAddr string        `mapstructure:"metricsListenAddr" default:"0.0.0.0:8080"`
	SecretStore       *SecretConfig `mapstructure:"secret"`
	SentryConf        SentryConfig  `mapstructure:"sentry"`
	CMKArn            string        `mapstructure:"cmkArn" required:"true"`
	DBEnv             string        `mapstructure:"dbEnv" default:"dev"`

	// secret salt conf, managed by aws secret manager, no need to config in k8s configmap crd
	SaltSecret string `mapstructure:"saltSecret" required:"true"`

	/* ================ following fields no need to config ================ */

	FrontendDNS string `mapstructure:"frontendDNS"` // no need to config
	BackendDNS  string `mapstructure:"backendDNS"`  // no need to config
	// If EnableEmailProviderBlocklists is true, user cannot register using the email address suffix in the dbbas.email_provider_blocklists table
	EnableEmailProviderBlocklists  bool    `mapstructure:"enableEmailProviderBlocklists" default:"false"`             // no need to config
	PocManualBackupReservedDays    *int    `mapstructure:"pocManualBackupReservedDays"`                               // no need to config
	PocAutoBackupReservedDays      *int    `mapstructure:"pocAutoBackupReservedDays"`                                 // no need to config
	OnDemandAutoBackupReservedDays *int    `mapstructure:"onDemandAutoBackupReservedDays"`                            // no need to config
	ManagementPortalInitUserEmail  *string `mapstructure:"managementPortalInitUserEmail" default:"cloud@pingcap.com"` // no need to config
	// BizOpsTeamEmail is the email of business ops team
	BizOpsTeamEmail string `mapstructure:"bizOpsTeamEmail"` // no need to config
	// whitelist for functions cdc to mysql and cdc to kafka
	EnableDataStreamToMysql []uint64 `mapstructure:"enableDataStreamToMysql"`           // no need to config
	EnableDataStreamToKafka []uint64 `mapstructure:"enableDataStreamToKafka"`           // no need to config
	EnableReplication       []uint64 `mapstructure:"enableReplication"`                 // no need to config
	EnableAuditLog          []uint64 `mapstructure:"enableAuditLog"`                    // no need to config
	UsePrivilegedTiDB       bool     `mapstructure:"usePrivilegedTiDB" default:"false"` // no need to config
	// check if loaded remote config
	RemoteConfigEnabled bool `mapstructure:"remoteConfigEnabled"` // no need to config
}

type SentryConfig struct {
	DSN         string `mapstructure:"dsn"`
	Environment string `mapstructure:"env"`
	LogLevel    string `mapstructure:"logLevel" default:"warn"`
}

type SessionConfig struct {
	// A secret to encrypt or derive sessions.
	// Currently only Debug Portal implements session.
	Secret string `mapstructure:"secret"`
}

type ImportConfig struct {
	MachineType      string `mapstructure:"machineType" default:"c5.9xlarge"`
	GCPMachineType   string `mapstructure:"gcpMachineType" default:"c2-standard-30"`
	StorageRequest   string `mapstructure:"storageRequest" default:"15Ti"`
	SkipPreCheck     bool   `mapstructure:"skipPreCheck"`
	SkipBanMyBuckets bool   `mapstructure:"skipBanMyBuckets"`
}

type ReplicationConfig struct {
	// machine support for the CDC
	AwsMachineType string `mapstructure:"awsMachineType" default:"c5.2xlarge"`
	GcpMachineType string `mapstructure:"gcpMachineType" default:"e2-standard-8"`
	StorageRequest string `mapstructure:"storageRequest" default:"1Ti"`
}

type SecretConfig struct {
	SecretKey      string `mapstructure:"secretKey"`
	ExtraSecretKey string `mapstructure:"extraSecretKey"`
	Region         string `mapstructure:"region"`
}

type GrafanaConfig struct {
	Server           string `mapstructure:"server"  default:"https://grafana.oauth.dev.shared.aws.tidbcloud.com/"`
	APIKey           string `mapstructure:"apiKey"`
	TidbDashboardTag string `mapstructure:"tidbDashboardTag" default:"tidb-mixin"`
}

// infra configurations
type InfraConfig struct {
	// dbaas central service region
	Region            string `mapstructure:"region" required:"true" default:"us-west-2"`
	CMKArn            string `mapstructure:"cmkArn" required:"true"`
	AwsPublicHZDomain string `mapstructure:"awsPublicHZDomain" required:"true"`
	GcpPublicHZDomain string `mapstructure:"gcpPublicHZDomain" required:"true"`
	AwsPublicHZID     string `mapstructure:"awsPublicHZID" required:"true"`
	GcpPublicHZID     string `mapstructure:"gcpPublicHZID" required:"true"`
	GcpProject        string `mapstructure:"gcpProject" required:"true"`

	ConfigServiceURL string `mapstructure:"configServiceURL" required:"true" default:"http://config-service.gitops:8090"`

	EnableTopSQL bool `mapstructure:"enableTopSQL" required:"false" default:"true"`
}

type ZendeskConfig struct {
	EnableZendesk   bool   `mapstructure:"enableZendesk" default:"false"`
	ZendeskEmail    string `mapstructure:"zendeskEmail"`
	ZendeskDomain   string `mapstructure:"zendeskDomain"`
	ZendeskAPIToken string `mapstructure:"zendeskAPIToken"`
}

type SalesforceConfig struct {
	EnableSalesforce       bool   `mapstructure:"enableSalesforce" default:"false"`
	SalesforceDomain       string `mapstructure:"salesforceDomain"`
	SalesforceClientID     string `mapstructure:"salesforceClientID"`
	SalesforceClientSecret string `mapstructure:"salesforceClientSecret"`
	SalesforceUsername     string `mapstructure:"salesforceUsername"`
	SalesforcePassword     string `mapstructure:"salesforcePassword"`
}

type Auth0Config struct {
	Auth0DatabaseConnectionName string `mapstructure:"auth0DatabaseConnectionName" default:"custom-email"` // no need to config

	Auth0Domain   string `mapstructure:"auth0Domain" required:"true"`
	Auth0Audience string `mapstructure:"auth0Audience" required:"true"`
	Auth0Secret   string `mapstructure:"auth0Secret" required:"true"`
}

type DebugPortalConfig struct {
	OAuthClientID         string      `mapstructure:"oAuthClientID" required:"true"`
	OAuthClientSecret     string      `mapstructure:"oAuthClientSecret" required:"true"`
	OAuthScopes           string      `mapstructure:"oAuthScopes" required:"true"`
	OAuthAuthorizationURL string      `mapstructure:"oAuthAuthorizationURL" required:"true"`
	OAuthTokenURL         string      `mapstructure:"oAuthTokenURL" required:"true"`
	OAuthUserInfoURL      string      `mapstructure:"oAuthUserInfoURL" required:"true"`
	OAuthStateSecret      string      `mapstructure:"oAuthStateSecret" required:"true"`
	SignOutURL            string      `mapstructure:"signOutURL" required:"true"`
	DisableAuthN          bool        `mapstructure:"disableAuthN" required:"true"`
	SlowQueryDB           MysqlConfig `mapstructure:"slowQueryDB" required:"true"`
	TopSqlTidbConfig      MysqlConfig `mapstructure:"topSQLTiDB" required:"true"`
}

type BillingConfig struct {
	// The billing system base url
	Billing2BaseURL       string            `mapstructure:"billing2BaseURL" default:"http://billing2:18888" required:"true"`
	Billing2URLPrefix     string            `mapstructure:"billing2URLPrefix" default:"/api/v1/billing" required:"true"`
	BillingPackageIDs     BillingPackageIDs `mapstructure:"billingPackageIDs"`
	EnablePOCEndedCleanup bool              `mapstructure:"enablePOCEndedCleanup" default:"true"`
	EnableCDCTCUMetering  bool              `mapstructure:"enableCDCTCUMetering" default:"true"`
	CDCTCUMappingTable    [][]int           `mapstructure:"cdcTCUMappingTable" default:"[[0,2], [6,3], [15,4]]"`
}

type BillingPackageIDs struct {
	OnDemand uint64 `mapstructure:"onDemand"`
	Poc      uint64 `mapstructure:"poc"`
	DevTier  uint64 `mapstructure:"devTier"`
}

type ProxyConfig struct {
	Auth0Domain       string `mapstructure:"auth0Domain" required:"true"`
	Auth0ClientID     string `mapstructure:"auth0ClientID" required:"true"`
	Auth0ClientSecret string `mapstructure:"auth0ClientSecret" required:"true"`
	Auth0Audience     string `mapstructure:"auth0Audience" required:"true"`
}

type AwsConfig struct {
	PCAArn                  string `mapstructure:"pcaArn" required:"true"`
	PCARegion               string `mapstructure:"pcaRegion" required:"true"`
	Region                  string `mapstructure:"region" required:"true"`
	AccountID               string `mapstructure:"accountID" required:"true"`
	ProjectID               string `mapstructure:"projectID" required:"true"`
	ReporterAccessKeyID     string `mapstructure:"reporterAccessKeyID" required:"true"`
	ReporterSecretAccessKey string `mapstructure:"reporterSecretAccessKey" required:"true"`
}

type GardenerConfig struct {
	GcpMasterType  string `mapstructure:"gcpMasterType" default:"n1-standard-2"`
	GcpMasterCount int32  `mapstructure:"gcpMasterCount" default:"1"`
	AwsMasterType  string `mapstructure:"awsMasterType" default:"t3.medium"`
	AwsMasterCount int32  `mapstructure:"awsMasterCount" default:"1"`

	GardenerProjectName string `mapstructure:"gardenerProjectName" default:"core" required:"true"`
	// The base domain of gardener
	GardenBaseDomain string `mapstructure:"gardenBaseDomain" default:"garden.shared.aws.tidbcloud.com"`
	// kubeconfig file for base cluster, ignore if in cluster
	NodeImage        string `mapstructure:"nodeImage"`
	KubeConfigPath   string `mapstructure:"kubeConfigPath"`
	StorageNodeImage string `mapstructure:"storageNodeImage"`
}

// InfraAPIConfig is the configration items for infra API operations.
type InfraAPIConfig struct {
	// kubeconfig file for the infra API server, ignore this to use the default secret
	KubeConfigPath string `mapstructure:"kubeConfigPath"`

	// ref https://github.com/tidbcloud/infra-api/pull/79
	// Enable this too keep the 'key' of resources do not change in infra-api.
	// will use projectID@dbaas as projectID@infra-api
	ProjectIDAsInfraProjectID bool `mapstructure:"projectIDAsInfraProjectID"`
}

// NeedInit returns true if we need to initialize the infra API.
func (ic *InfraAPIConfig) NeedInit() bool {
	return true
}

type MysqlConfig struct {
	Host     string `mapstructure:"host" default:"host"`
	User     string `mapstructure:"user" default:"root"`
	Port     uint16 `mapstructure:"port" default:"4000"`
	Password string `mapstructure:"password" required:"true"`
	Database string `mapstructure:"database" default:"dbaas"`
}

type TLSConfig struct {
	TlsCA   string `json:"ca.crt"`
	TlsCert string `json:"tls.crt"`
	TlsKey  string `json:"tls.key"`
}

type O11yGlobalServerConfig struct {
	Url          string `mapstructure:"url" required:"true"`
	DomainSuffix string `mapstructure:"domainSuffix" required:"true"`
	BizType      string `mapstructure:"bizType" required:"true"`

	Auth0Domain       string `mapstructure:"auth0Domain" required:"true"`
	Auth0Audience     string `mapstructure:"auth0Audience" required:"true"`
	Auth0ClientID     string `mapstructure:"auth0ClientID" required:"true"`
	Auth0ClientSecret string `mapstructure:"auth0ClientSecret" required:"true"`

	RegionalDataServerUriPrefix string      `mapstructure:"regionalDataServerUriPrefix" required:"true"`
	MetricsApiUrl               string      `mapstructure:"metricsApiUrl" required:"true"`
	AllowList                   []entity.ID `mapstructure:"allowList" required:"false"`
	BlockList                   []entity.ID `mapstructure:"blockList" required:"false"`
}
