package cloudevent

import (
	"encoding/json"
)

type Topic string

// TopicClusterEvent is the topic for cluster event, TopicMaintenanceWindowEvent is the topic for maintenance window event
// both internal pub sub and event bus, cluster event will be published to the topic named TopicClusterEvent
// both internal pub sub and event bus, maintenance window event will be published to the topic named TopicMaintenanceWindowEvent
const (
	TopicClusterEvent Topic = "ClusterEvent"
)

type (
	EventType string
)

// Note 1. notify clinic service team if you add or remove some events
// for more detail: refer to: https://pingcap.feishu.cn/wiki/wikcnJAZ642PH32aQzL8PKjtmge
const (
	EventTypeCreating     EventType = "ClusterCreating" // cluster is creating and created into metadb
	EventTypeCreated      EventType = "ClusterCreated"  // cluster is created and began to serve
	EventTypeInitializing EventType = "ClusterInitializing"
	EventTypeInitialized  EventType = "ClusterInitialized"
	EventTypePreparing    EventType = "ClusterPreparing"
	EventTypePrepared     EventType = "ClusterPrepared"
	EventTypeRestoring    EventType = "ClusterRestoring"
	EventTypeRestored     EventType = "ClusterRestored"
	EventTypeLaunching    EventType = "ClusterLaunching"
	EventTypeLaunched     EventType = "ClusterLaunched"
	EventTypeNormal       EventType = "ClusterNormal"
	// EventTypeApplying and EventTypeApplied are used for the operation of applying the cluster configuration or version.
	EventTypeApplying         EventType = "ClusterApplying"
	EventTypeApplied          EventType = "ClusterApplied"
	EventTypeShutdownUpgrade  EventType = "ClusterShutdownUpgrade"
	EventTypeShutdownUpgraded EventType = "ClusterShutdownUpgraded"
	// EventTypeScheduledResume is used for the operation of scheduled resume.
	EventTypeScheduledResume         EventType = "ClusterScheduledResume"
	EventTypePausing                 EventType = "ClusterPausing"
	EventTypePaused                  EventType = "ClusterPaused"
	EventTypeResuming                EventType = "ClusterResuming"
	EventTypeResumed                 EventType = "ClusterResumed"
	EventTypeScaling                 EventType = "ClusterScaling"
	EventTypeScaled                  EventType = "ClusterScaled"
	EventTypeDeleting                EventType = "ClusterDeleting"
	EventTypeDeleted                 EventType = "ClusterDeleted"
	EventTypeCleared                 EventType = "ClusterCleared"
	EventTypeVolumeSnapshotRestoring EventType = "ClusterVolumeSnapshotRestoring"
	EventTypeVolumeSnapshotRestored  EventType = "ClusterVolumeSnapshotRestored"
	EventTypeInsufficientResource    EventType = "ClusterInsufficientResource"
	// Serverless events
	EventTypeUpdatingPublicEndpoint EventType = "ClusterPublicEndpointUpdating"
	EventTypeUpdatedPublicEndpoint  EventType = "ClusterPublicEndpointUpdated"
	EventTypeUpdatingCapacity       EventType = "ClusterCapacityUpdating"
	EventTypeUpdatedCapacity        EventType = "ClusterCapacityUpdated"
	EventTypeUpdatingAuditLogConfig EventType = "ClusterAuditLogConfigUpdating"
	EventTypeUpdatedAuditLogConfig  EventType = "ClusterAuditLogConfigUpdated"
)

type ClusterComponent struct {
	ComponentType     string `json:"component_type"`
	SpuName           string `json:"tier_name"` // the name of tier used by this component, for example: "8C16G"
	SpuDisplayName    string `json:"tier_display_name"`
	SpuKey            string `json:"tier_key"`      // the key of tier, for example: '2C4G:DEPLOY_TYPE_DEDICATED:COMPONENT_TYPE_TIKV'
	SkuKey            string `json:"tier_unit_key"` // the key of tier unit, for example: 'aws:tikv:t4g.medium:gp3:4000:400'
	Quantity          uint32 `json:"quantity"`      // the node quantity of this component
	StorageSizeGi     uint32 `json:"storage_size_gi"`
	AdditionalIops    uint32 `json:"additional_iops"` // data disk additional iops, only for iops mapping dynamic storage
	VolumeType        string `json:"volume_type"`
	RaftLogVolumeType string `json:"raft_log_volume_type"`
	RaftLogIops       uint32 `json:"raft_log_iops"` // raft log disk iops
}
type ClusterTopology struct {
	Components       map[string]*ClusterComponent `json:"components"`
	ExTidbNodeGroups []*TidbNodeGroup             `json:"ex_tidb_node_groups,omitempty"` // without default tidb node group
}
type TidbNodeGroup struct {
	ID                    uint64 `json:"id"`
	DisplayName           string `json:"display_name"`
	TidbNodeQuantity      uint32 `json:"tidb_node_quantity"`
	TiProxyQuantity       uint32 `json:"tiproxy_node_quantity"`
	TiProxySpuName        string `json:"tiproxy_tier_name"`
	TiProxySpuDisplayName string `json:"tiproxy_tier_display_name"`
}
type EventExtraInfo struct {
	DurationSeconds *int64 `json:"duration_seconds,string,omitempty"`
	// These fields below are only available for ClusterScaling event now.
	TopologyBefore *ClusterTopology `json:"topology_before,omitempty"`
	TopologyAfter  *ClusterTopology `json:"topology_after,omitempty"`
	// These fields below are only available for Upgrade event now.
	OldVersion *string `json:"old_version,omitempty"`
	NewVersion *string `json:"new_version,omitempty"`
	// These fields below are only available for Resume event now.
	PausePlanType string `json:"pause_plan_type,omitempty"`
	// These fields below are only available for ClusterAuditLogConfigUpdating and ClusterAuditLogConfigUpdated event now.
	AuditLogConfig string `json:"audit_log_config,omitempty"`
}

type ClusterEvent struct {
	TenantID  uint64 `json:"tenant_id,string"`
	ProjectID uint64 `json:"project_id,string"`
	ClusterID uint64 `json:"cluster_id,string"`
	// The operator's userId who did an operation which result in this event.
	// It may be zero that presents the operator is unknown or this event without operator.
	OperatorID       uint64 `json:"operator_id,string"`
	UserEmail        string `json:"user_email"`
	OpenAPIPublicKey string `json:"openapi_public_key"`
	// id of operation, it is used to associate with cluster_operation record.
	// It may be zero that presents this event without any cluster operation.
	// NOTE 1: Due to some technological problem, this field always is 0 in xxx-ing event.
	OperationID      uint64          `json:"operation_id,string"`
	IsDevTier        bool            `json:"is_dev_tier"`
	Status           string          `json:"status"` // refer to idl/core/core/core.proto:ClusterStatus
	EventType        EventType       `json:"event_type"`
	EventCreatedAtMs int64           `json:"event_created_at_ms,string"` // unix timestamp in milliseconds t.UnixMilli()
	ExtraInfo        *EventExtraInfo `json:"extra_info,omitempty"`
	ServicePlan      string          `json:"service_plan,omitempty"`
	ClusterType      string          `json:"cluster_type,omitempty"`
}

type ClusterType string

const (
	ClusterTypeTidbxInstance     = "tidbx_instance"
	ClusterTypeDedicatedCluster  = "dedicated_cluster"
	ClusterTypeTidbxResourcePool = "tidbx_resource_pool"
)

func (ev *ClusterEvent) MarshalJsonPayload() (string, error) {
	bs, e := json.Marshal(ev)
	return string(bs), e
}

func (ev *ClusterEvent) SetEventCreatedAtMs(ms int64) {
	ev.EventCreatedAtMs = ms
}

func (ev *ClusterEvent) GetEventCreatedAtMs() int64 {
	return ev.EventCreatedAtMs
}

func (ev *ClusterEvent) GetTargetTopic() Topic {
	return TopicClusterEvent
}

func (ev *ClusterEvent) GetEventType() string {
	return string(ev.EventType)
}
