package structs

import (
	"strings"
	"time"

	"github.com/pingcap/log"
	"github.com/tidbcloud/observability/pkg/common/constants"
	"github.com/tidbcloud/pkgv2/gormutil"
	"go.uber.org/zap"
)

type ServiceInfo struct {
	ServerName           string                            `json:"serverName"`
	Port                 int                               `json:"port"`
	MetricsPort          int                               `json:"metricsPort"`
	DefaultOversell      float64                           `json:"defaultOversell"`
	Vendor               string                            `json:"vendor"`
	Region               string                            `json:"region"`
	LogicalRegionName    string                            `json:"logicalRegionName"`
	DomainPostfix        string                            `json:"domainPostfix"`
	Host                 string                            `json:"host"`
	Env                  string                            `json:"env"`
	LogDir               string                            `json:"logDir"`
	LogLevel             string                            `json:"logLevel"`
	EnableHttps          bool                              `json:"enableHttps"`
	Development          bool                              `json:"development"`
	SelfMonitorEndpoint  string                            `json:"selfMonitorEndpoint"`
	Certificate          CertificateInfo                   `json:"certificate"`
	AZConfig             map[string]AvailabilityZoneConfig `json:"azconfig"`
	MonitorSpec          map[string]MonitorSpec            `json:"monitorSpec"`
	AccountInfo          AccountInfoConfig                 `json:"accountInfo"`
	VMClusterInfo        []VictoriaMetricsCluster          `json:"vmClusterInfo"`
	AlertManagerInfo     AlertManagerConfig                `json:"alertManagerInfo"`
	SNSInfo              SNSConfig                         `json:"snsConfig"`
	BizTypeConfigs       map[string]BizTypeConfig          `json:"bizTypeConfigs"`
	AlertRuleCacheConfig OverlayAlertRuleCacheConfig       `json:"alertRuleCacheConfig"`
	ControllerConfig     ControllerConfig                  `json:"controllerConfig"`
	BYOCVPCPeering       BYOCVPCPeeringConfig              `json:"byocVpcPeering" yaml:"byocVpcPeering"`
}

type BYOCVPCPeeringConfig struct {
	RouteTableIDs []string `json:"routeTableIDs" yaml:"routeTableIDs"`
}

func (p ServiceInfo) IsDevelopment() bool {
	return !(p.Env == constants.EnvProd)
}

type CertificateInfo struct {
	CrtFilePath string
	KeyFilePath string
}

type AvailabilityZoneConfig struct {
	EndpointServiceID    string `json:"endpointServiceID" yaml:"endpointServiceID"`
	IngressClassName     string `json:"ingressClassName" yaml:"ingressClassName"`
	ReadIngressClassName string `json:"readIngressClassName" yaml:"readIngressClassName"`
	DnsName              string `json:"dnsName" yaml:"dnsName"`
	DefaultDataAZ        bool   `json:"defaultDataAZ" yaml:"defaultDataAZ"`
	SellOut              bool   `json:"sellOut" yaml:"sellOut"`
}

type MonitorSpec struct {
	Cpu                 string  `json:"cpu" yaml:"cpu"`
	Memory              string  `json:"memory" yaml:"memory"`
	InitialStorage      string  `json:"initialStorage" yaml:"initialStorage"`
	MaxQueryConcurrency *int32  `json:"maxQueryConcurrency" yaml:"maxQueryConcurrency"`
	MaxQuerySamples     *int32  `json:"maxQuerySamples" yaml:"maxQuerySamples"`
	MaxQueueSize        *int32  `json:"maxQueueSize" yaml:"maxQueueSize"`
	OverSell            float64 `json:"overSell" yaml:"overSell"`
	IsDefault           bool    `json:"isDefault" yaml:"isDefault"`
}

type VictoriaMetricsCluster struct {
	VMClusterName string `json:"vmClusterName" yaml:"vmClusterName"`
}

type ThanosObjectStorageSecret struct {
	Type   string                    `json:"type" yaml:"type"`
	Config ThanosObjectSotrageConfig `json:"config" yaml:"config"`
	Prefix string                    `json:"prefix" yaml:"prefix"`
}

type ThanosObjectSotrageConfig struct {
	Bucket         string `json:"bucket" yaml:"bucket"`
	Endpoint       string `json:"endpoint" yaml:"endpoint"`
	AwsSdkAuth     bool   `json:"aws_sdk_auth" yaml:"aws_sdk_auth"`
	StorageAccount string `json:"storage_account" yaml:"storage_account"`
	Container      string `json:"container" yaml:"container"`
}

type AccountInfoConfig struct {
	OidcARN           string `json:"oidc-arn" yaml:"oidc-arn"`
	Oidc              string `json:"oidc" yaml:"oidc"`
	Env               string `json:"env" yaml:"env"`
	Project           string `json:"project" yaml:"project"`
	Account           string `json:"account" yaml:"account"`
	Region            string `json:"region" yaml:"region"`
	LogicalRegionName string `json:"logicalRegionName" yaml:"logicalRegionName"`
	DomainPostfix     string `json:"domainPostfix" yaml:"domainPostfix"`
	// azure subscriptionID
	SubscriptionID string `json:"subscriptionID" yaml:"subscriptionID"`
	// azure resourceGroup Name for private link service, use aks's resourceGroup
	ResourceGroup string `json:"resourceGroup" yaml:"resourceGroup"`
	// azure storage account name for o11y
	StorageAccount string `json:"storageAccount" yaml:"storageAccount"`
	// azure resourceGroup Name for blob storage
	BlobStorageResourceGroup string `json:"blobStorageResourceGroup" yaml:"blobStorageResourceGroup"`
	// alicloud OSS bucket redundancy type
	OSSRedundancyType string `json:"ossRedundancyType" yaml:"ossRedundancyType"`
}

type BizTypeAccount struct {
	BizType string `json:"biz_type" yaml:"biz_type"`
	RoleArn string `json:"role_arn" yaml:"role_arn"`
}

type AlertManagerConfig struct {
	NameSpace string `json:"namespace" yaml:"namespace"`
	Name      string `json:"name" yaml:"name"`
	Port      string `json:"port" yaml:"port"`
}

type SyncAlertRuleConfig struct {
	MaxWorkers        int           `json:"maxWorkers" yaml:"maxWorkers"`
	MaxJobs           int           `json:"maxJobs" yaml:"maxJobs"`
	QueryClusterLimit int64         `json:"queryClusterLimit" yaml:"queryClusterLimit"`
	FailedRetryTimes  int           `json:"failedRetryTimes" yaml:"failedRetryTimes"`
	RotationInterval  time.Duration `json:"rotationInterval" yaml:"rotationInterval"`
	ResyncPeriod      time.Duration `json:"resyncPeriod" yaml:"resyncPeriod"`
	//alertrules automatic synchronization function switch, true on or false off
	Enabled bool `json:"enabled" yaml:"enabled"`
}

type OverlayAlertRuleCacheConfig struct {
	ExpireTime              time.Duration `json:"expireTime" yaml:"expireTime"`
	MaxItems                int           `json:"maxItems" yaml:"maxItems"`
	MaxAlertRulesPerCluster int           `json:"maxAlertRulesPerCluster" yaml:"maxAlertRulesPerCluster"`
	Enabled                 bool          `json:"enabled" yaml:"enabled"`
	SleepTime               time.Duration `json:"sleepTime" yaml:"sleepTime"`
	MaxDeletionPerCycle     int           `json:"maxDeletionPerCycle" yaml:"maxDeletionPerCycle"`
}

// SNSConfig defines the global SNS config we used
type SNSConfig struct {
	Region  string `json:"region" yaml:"region"`
	Url     string `json:"url" yaml:"url"`
	RoleArn string `json:"roleArn" yaml:"roleArn"`
}

type BizTypeConfig struct {
	BizType                    string `json:"bizType" yaml:"bizType"`
	ExternalApiAuthUrlTemplate string `json:"externalApiAuthUrlTemplate" yaml:"externalApiAuthUrlTemplate"`
	AgentManagerARN            string `json:"agentManagerARN" yaml:"agentManagerARN"`
	MonitorPromRuleTemplate    string `json:"monitorPromRuleTemplate" yaml:"monitorPromRuleTemplate"`

	MonitorReplicas  int    `json:"monitorReplicas" yaml:"monitorReplicas"`
	MonitorVersion   string `json:"monitorVersion" yaml:"monitorVersion"`
	MonitorRetention string `json:"monitorRetention" yaml:"monitorRetention"`
	SpecificBucket   string `json:"specificBucket" yaml:"specificBucket"`
	ExternalBucket   string `json:"externalBucket" yaml:"externalBucket"`
	MultiTenancyRule bool   `json:"multiTenancyRule" yaml:"multiTenancyRule"`

	InheritedIAM           string                 `json:"inheritedIAM" yaml:"inheritedIAM"`
	DataplaneRole          string                 `json:"dataplaneRole" yaml:"dataplaneRole"`
	OmitTenancyReadIngress OmitTenancyReadIngress `json:"omitTenancyReadIngress" yaml:"omitTenancyReadIngress"`
	SkipAlertRule          bool                   `json:"skipAlertRule" yaml:"skipAlertRule"`
	UseRDS                 bool                   `json:"useRDS" yaml:"useRDS"`
	// O11yGlobalDSHostName is the hostname of o11y global data server, used for pingcap internal access.
	O11yGlobalDSHostName     string `json:"o11yGlobalDSHostName" yaml:"o11yGlobalDSHostName"`
	GlobalDataServerHostname string `json:"globalDataServerHostname" yaml:"globalDataServerHostname"`
}

type OmitTenancyReadIngress struct {
	AllOmit     bool     `json:"allOmit" yaml:"allOmit"`
	OmitTenants []string `json:"omitTenants" yaml:"omitTenants"`
}

type ControllerConfig struct {
	IntegrationTaskConfig IntegrationTaskConfig      `json:"integrationTaskConfig" yaml:"integrationTaskConfig"`
	ServerlessConfig      ServerlessControllerConfig `json:"serverlessConfig" yaml:"serverlessConfig"`
}

type IntegrationTaskConfig struct {
	Enable            bool   `json:"enable" yaml:"enable"`
	JobManagerImage   string `json:"jobManagerImage" yaml:"jobManagerImage"`
	JobManagerIAMRole string `json:"jobManagerIAMRole" yaml:"jobManagerIAMRole"`
	VectorAgentImage  string `json:"vectorAgentImage" yaml:"vectorAgentImage"`
	VectorS3SyncImage string `json:"vectorS3SyncImage" yaml:"vectorS3SyncImage"`
	VectorRoleARN     string `json:"vectorRoleARN" yaml:"vectorRoleARN"`
	// SharedBucketTenantIDs keeps listed tenants on the shared external bucket.
	SharedBucketTenantIDs []string `json:"sharedBucketTenantIDs" yaml:"sharedBucketTenantIDs"`
}

// IsSharedBucketTenant reports whether tenantID should keep using the shared external bucket.
func (c IntegrationTaskConfig) IsSharedBucketTenant(tenantID string) bool {
	tenantID = strings.TrimSpace(tenantID)
	if tenantID == "" {
		return false
	}
	for _, sharedTenantID := range c.SharedBucketTenantIDs {
		if strings.TrimSpace(sharedTenantID) == tenantID {
			return true
		}
	}
	return false
}

type ServerlessControllerConfig struct {
	EnableRDSClient bool       `json:"enableRDSClient" yaml:"enableRDSClient"`
	MaxConcurrency  int        `json:"maxConcurrency" yaml:"maxConcurrency"`
	RDSSecretArn    string     `json:"rdsSecretArn" yaml:"rdsSecretArn"`
	RdsConfig       *RdsConfig `json:"rdsConfig" yaml:"rdsConfig"`
}

type RdsConfig struct {
	Host         string `json:"host" yaml:"host"`
	Port         uint16 `json:"port" yaml:"port"`
	UserName     string `json:"username" yaml:"username"`
	Password     string `json:"password" yaml:"password"`
	Dbname       string `json:"dbname" yaml:"dbname"`
	TLSConfigKey string `json:"tlsConfigKey" yaml:"tlsConfigKey"`
}

func (r *RdsConfig) ToGormutilConfig() *gormutil.Config {
	connCfg := &gormutil.Config{
		User:         r.UserName,
		Host:         r.Host,
		Database:     r.Dbname,
		Password:     r.Password,
		Port:         r.Port,
		TLSConfigKey: r.TLSConfigKey,
	}

	switch log.GetLevel() {
	case zap.DebugLevel:
		connCfg.LogLevel = "info"
		connCfg.EnableDetailedLog = true
	case zap.InfoLevel:
		connCfg.LogLevel = "info"
	case zap.WarnLevel:
		connCfg.LogLevel = "warn"
	case zap.ErrorLevel:
		connCfg.LogLevel = "error"
	case zap.FatalLevel:
		connCfg.LogLevel = "fatal"
	default:
		connCfg.LogLevel = "info"
	}

	return connCfg
}
