package config

import (
	"sync/atomic"

	"github.com/pingcap/dbaas/pkg/ratecontroller/types"
)

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

type CentralConfig struct {
	ServerConfig      ServerConfig      `mapstructure:"server"`
	SessionConfig     SessionConfig     `mapstructure:"session"`
	GrpcConfig        GrpcConfig        `mapstructure:"grpc"`
	MysqlConfig       MysqlConfig       `mapstructure:"mysql"`
	GardenerConfig    GardenerConfig    `mapstructure:"gardener"`
	InfraAPIConfig    InfraAPIConfig    `mapstructure:"infraAPI"`
	AwsConfig         AwsConfig         `mapstructure:"aws"`
	BillingConfig     BillingConfig     `mapstructure:"billing"`
	ProxyConfig       ProxyConfig       `mapstructure:"proxy"`
	InfraConfig       InfraConfig       `mapstructure:"infra"`
	Auth0Config       Auth0Config       `mapstructure:"auth0"`
	DebugPortalConfig DebugPortalConfig `mapstructure:"debugPortal"`
	ZendeskConfig     ZendeskConfig     `mapstructure:"zendesk"`
	SalesforceConfig  SalesforceConfig  `mapstructure:"salesforce"`
	GrafanaConfig     GrafanaConfig     `mapstructure:"grafana"`
	ImportConfig      ImportConfig      `mapstructure:"import"`
	ReplicationConfig ReplicationConfig `mapstructure:"replication"`
	HibernationConfig HibernationConfig `mapstructure:"hibernation"`
	RateControlConfig RateControlConfig `mapstructure:"rateControl"`
	MarketPlaceConfig MarketPlaceConfig `mapstructure:"marketPlace"`
}

type GrpcConfig struct {
	CoreSvcAddr string `mapstructure:"coreSvcAddr" default:"core-server-grpc:8888"`
}

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"`

	FrontendDNS string `mapstructure:"frontendDNS" validate:"required"`
	BackendDNS  string `mapstructure:"backendDNS" validate:"required"`

	// 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"`

	ManifestDirPrefix string `mapstructure:"manifestDirPrefix"`
	Stage             string `mapstructure:"stage" validate:"required"`
	// central server cidr
	CentralCIDR []string `mapstructure:"centralCIDR" default:"[\"0.0.0.0/0\", \"0.0.0.0/1\"]"`
	GrpcPort    int      `mapstructure:"grpcPort" default:"10000"`
	//the central metrics port
	MetricsPort uint16 `mapstructure:"metricsPort" default:"9090"`
	// session secret salt conf
	SaltSecret string `mapstructure:"saltSecret" required:"true"`
	// mailgun conf
	MailGunApiKey string `mapstructure:"mailGunApiKey" required:"true"`
	// sendgrid conf
	SendgridApiKey string `mapstructure:"sendgridApiKey" required:"true"`

	EnableRecaptcha bool `mapstructure:"enableRecaptcha" default:"false"`

	// recaptcha secret conf
	RecaptchaSecret string `mapstructure:"recaptchaSecret" required:"true"`

	SentryConf SentryConfig `mapstructure:"sentry"`

	SecretStore       *SecretConfig `mapstructure:"secret"`
	TopSQLSecretStore *SecretConfig `mapstructure:"topSQLSecret"`

	PocManualBackupReservedDays *int `mapstructure:"pocManualBackupReservedDays" validate:"required"`

	PocAutoBackupReservedDays *int `mapstructure:"pocAutoBackupReservedDays" validate:"required"`

	OnDemandAutoBackupReservedDays *int `mapstructure:"onDemandAutoBackupReservedDays" validate:"required"`

	ManagementPortalInitUserEmail *string `mapstructure:"managementPortalInitUserEmail" default:"cloud@pingcap.com"`

	// BizOpsTeamEmail is the email of business ops team
	BizOpsTeamEmail string `mapstructure:"bizOpsTeamEmail"`

	CentralRoleARN string `mapstructure:"centralRoleARN" validate:"required"`

	// listen addr
	AdminListenAddr          string `mapstructure:"adminListenAddr" default:"0.0.0.0:8080"`
	MetricsListenAddr        string `mapstructure:"metricsListenAddr" default:"0.0.0.0:8080"`
	InternalPortalListenAddr string `mapstructure:"internalPortalListenAddr" default:"0.0.0.0:8081"`

	// thanos addr
	ThanosAddr string `mapstructure:"thanosAddr" default:"http://thanos-query.monitoring:9090"`

	// limited project cidr
	LimitedProjectCIDR []string `mapstructure:"limitedProjectCIDR"`

	// whitelist for functions cdc to mysql and cdc to kafka
	EnableDataStreamToMysql []uint64 `mapstructure:"enableDataStreamToMysql"`
	EnableDataStreamToKafka []uint64 `mapstructure:"enableDataStreamToKafka"`
	EnableReplication       []uint64 `mapstructure:"enableReplication"`
	EnableAuditLog          []uint64 `mapstructure:"enableAuditLog"`
	EnableXAccount          []uint64 `mapstructure:"enableXAccount"`

	UsePrivilegedTiDB bool `mapstructure:"usePrivilegedTiDB" default:"false"`

	// check if loaded remote config
	RemoteConfigEnabled bool `mapstructure:"remoteConfigEnabled"`

	Project string `mapstructure:"project" default:"nightly"`

	CDNBucketPathPrefix string `mapstructure:"cdnBucketPathPrefix" default:"uploaded"`
	EnableCDNBucket     bool   `mapstructure:"enableCDNBucket" default:"true"`
	CDNBucket           string `mapstructure:"cdnBucket"`
	CDNHost             string `mapstructure:"cdnHost"`
	CDNFileContentType  string `mapstructure:"cdnFileContentType" default:"application/octet-stream"`
}

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" validate:"required"`
}

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"`
	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 {
	Auth0ManagementClientID     string `mapstructure:"auth0ManagementClientID" required:"true"`
	Auth0ManagementClientSecret string `mapstructure:"auth0ManagementClientSecret" required:"true"`
	Auth0DatabaseConnectionName string `mapstructure:"auth0DatabaseConnectionName" required:"true" default:"custom-email"`

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

	ManagementPortalAuth0Domain         string `mapstructure:"managementPortalAuth0Domain" required:"true"`
	ManagementPortalAuth0Audience       string `mapstructure:"managementPortalAuth0Audience" required:"true"`
	ManagementPortalAuth0Secret         string `mapstructure:"managementPortalAuth0Secret" required:"true"`
	ManagementPortalAuth0ClientAudience string `mapstructure:"managementPortalAuth0ClientAudience" 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:"false"`
	CDCTCUMappingTable    [][]int           `mapstructure:"cdcTCUMappingTable" default:"[[0,16], [48,24], [120,32], [169, 40]]"`
	DiscountDescription   string            `mapstructure:"discountDescription" default:""`
}

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"`
}
