package structs

import (
	"fmt"

	"github.com/tidbcloud/observability/pkg/common/constants"
)

type ObservabilityCluster struct {
	ClusterBaseInfo
	StorageInfo []StorageInfo            `json:"storageInfo" form:"storageInfo"`
	MonitorInfo MonitorInfo              `json:"monitorInfo" form:"monitorInfo"`
	AgentInfo   AgentInfo                `json:"agentInfo" form:"agentInfo"`
	AlertInfo   AlertInfo                `json:"alertInfo" form:"alertInfo"`
	Status      constants.ResourceStatus `json:"status" form:"status"`

	LastScaleTime map[string]string `json:"lastScaleTime" form:"lastScaleTime"`
}

type CommonReqInfo struct {
	Vendor constants.ProvidedVendor `json:"vendor" form:"vendor" validate:"required,max=16"`
	Region string                   `json:"region" form:"region" validate:"required,max=16"`
}

type ClusterBaseInfo struct {
	CommonReqInfo
	TenantID           string                       `json:"tenantID" form:"tenantID" validate:"required,max=20"`
	ProjectID          string                       `json:"projectID" form:"projectID" validate:"max=20"`
	ApplicationID      string                       `json:"applicationID" form:"applicationID" validate:"required,max=63"`
	BizType            string                       `json:"bizType" form:"bizType" validate:"required,max=32"`
	ID                 string                       `json:"id" form:"id" validate:"max=64"`
	Tags               []string                     `json:"tags" form:"tags"`
	Version            constants.VersionCode        `json:"version" form:"version"`
	ShareMode          constants.ShareMode          `json:"shareMode" form:"shareMode" validate:"required,oneof=exclusive shared virtual enhanced"`
	Note               string                       `json:"note" form:"note"`
	DataPropertyRights constants.DataPropertyRights `json:"dataPropertyRights" form:"dataPropertyRights" validate:"oneof=0 1"`
	InternalReadUri    string                       `json:"internalReadUri" form:"internalReadUri"`
	OpenReadUri        string                       `json:"openReadUri" form:"openReadUri"`
	MuteAlert          bool                         `json:"muteAlert" form:"muteAlert"`
}

type StorageInfo struct {
	BucketName string `json:"bucketName,omitempty" form:"bucketName,omitempty"`
	// Keep the Go field name for compatibility while the public API stays on storageAccount.
	StorageAccount string                          `json:"storageAccount,omitempty" form:"storageAccount,omitempty"`
	Category       constants.ObservabilityCategory `json:"category,omitempty" form:"category,omitempty"`
	DataARN        string                          `json:"dataARN,omitempty" form:"dataARN,omitempty"`
	ObjectPath     string                          `json:"objectPath,omitempty" form:"objectPath,omitempty"`
}

type MonitorInfo struct {
	SpecID string `json:"specID" form:"specID"`
	//Storage             string `json:"storage" form:"storage"`
	EndpointServiceName string `json:"endpointServiceName" form:"endpointServiceName"`
	DNSName             string `json:"dnsName" form:"dnsName"`
	VMAccountID         string `json:"vmAccountID" form:"vmAccountID"`
	VMProjectID         string `json:"vmProjectID" form:"vmProjectID"`
}

type AlertInfo struct {
	MuteAlert      bool   `json:"muteAlert" form:"muteAlert"`
	RuleTemplateID string `json:"ruleTemplateID" form:"ruleTemplateID"`
}

type AgentInfo struct {
	// o11y role for agents
	RoleARN string `json:"roleARN" form:"roleARN"`
	// TODO add more agent info if needed
}

type ClusterUniqueKey struct {
	BizType       string `json:"bizType" form:"bizType" validate:"required,max=32"`
	TenantID      string `json:"tenantID" form:"tenantID" validate:"required,max=20"`
	ProjectID     string `json:"projectID" form:"projectID" validate:"max=20"`
	ApplicationID string `json:"applicationID" form:"applicationID" validate:"required,max=63"`
}

func (k *ClusterUniqueKey) IsValid() bool {
	return len(k.BizType) > 0 &&
		len(k.TenantID) > 0 &&
		len(k.ApplicationID) > 0
}

func (k *ClusterUniqueKey) Splice() string {
	var projectID string
	if len(k.ProjectID) == 0 {
		// If ProjectID is not set, we can use a default value 0
		projectID = "0"
	} else {
		projectID = k.ProjectID
	}
	return fmt.Sprintf("%s/%s/%s/%s", k.BizType, k.TenantID, projectID, k.ApplicationID)
}

type ArchivedClusterInfo struct {
	ClusterBaseInfo
	VMAccountID string
	VMProjectID string
	StorageInfo []StorageInfo `json:"storageInfo" form:"storageInfo"`
}

// AgentEnvironment Describe the agent's deployment environment
type AgentEnvironment struct {
	ReleaseNameSpace string                    `json:"releaseNameSpace,omitempty" form:"releaseNameSpace,omitempty"`
	Dataplane        Dataplane                 `json:"dataplane" form:"dataplane"`
	AWS              *AWSAgentEnvironment      `json:"aws,omitempty" form:"aws,omitempty"`
	GCP              *GCPAgentEnvironment      `json:"gcp,omitempty" form:"gcp,omitempty"`
	Azure            *AzureAgentEnvironment    `json:"azure,omitempty" form:"azure,omitempty"`
	AliCloud         *AliCloudAgentEnvironment `json:"aliCloud,omitempty" form:"aliCloud,omitempty"`
}
type Dataplane struct {
	ClusterName string `json:"clusterName"`
	// +optional
	ClusterEndpoint string `json:"clusterEndpoint,omitempty"`
	// +optional
	ClusterCAData *string `json:"clusterCAData,omitempty"`
	// +optional
	// base64-encoded kubeconfig data
	ClusterKubeConfig *string `json:"clusterKubeConfig,omitempty"`
}
type AWSAgentEnvironment struct {
	VpcID           string   `json:"vpcID"`
	NodeSubnetIDs   []string `json:"nodeSubnetIDs"`
	SecurityGroupID string   `json:"securityGroupID"`
	Account         string   `json:"account"`
	OIDC            string   `json:"oidc"`
}

type AliCloudAgentEnvironment struct {
	VpcID           string   `json:"vpcID"`
	NodeSubnetIDs   []string `json:"nodeSubnetIDs"`
	SecurityGroupID string   `json:"securityGroupID"`
	Account         string   `json:"account"`
	OIDC            string   `json:"oidc"`
}

type GCPAgentEnvironment struct {
	NetworkName string   `json:"networkName"`
	GCPProject  string   `json:"gcpProject"`
	Subnets     []string `json:"subnets"`
}

type AzureAgentEnvironment struct {
	NetworkName    string `json:"networkName"`
	SubscriptionID string `json:"subscriptionID"`
	ResourceGroup  string `json:"resourceGroup"`
	// Subnet where private endpoint should be created
	Subnet string `json:"subnet"`
	// AKS OIDC issuer used for creating federated identity
	OIDC string `json:"oidc"`
}

// Observed is used to store the observed state of the tidb cluster for o11y autoscaling or configuration
// now we only need TiDBClusterTopology, TiDBVersion
type Observed struct {
	TiDBClusterTopology *ClusterTopologyType `json:"clusterTopology,omitempty"`
	TiDBVersion         string               `json:"tidbVersion,omitempty"`

	//TODO more to be added
}

type ClusterTopologyType struct {
	TiDB    TiDB     `json:"tidb"`
	PD      PD       `json:"pd"`
	TiKV    TiKV     `json:"tikv"`
	TiFlash *TiFlash `json:"tiflash,omitempty"`
}

type TiDB struct {
	Replicas int `json:"replicas"`
}

type PD struct {
	Replicas int `json:"replicas"`
}

type TiKV struct {
	Replicas int `json:"replicas"`
}

type TiFlash struct {
	Replicas int `json:"replicas"`
}
