package center

import (
	"fmt"
	"strconv"

	appconfig "github.com/tidbcloud/dataflow-service-ng/app/config"
	"github.com/tidbcloud/dataflow-service-ng/app/repo/entity"
	"github.com/tidbcloud/eventbus-datastruct/event"
)

var (
	brStartedMsg = "The %s task was started."
	brBasicMsg   = "The %s task was %s."
	brUnknownMsg = "The %s task status was updated."

	nameMsg = "Task name: %s."
)

type MsgKindType string

const (
	MysqlChangefeed MsgKindType = "mysql"
)

type MsgStatusType string

const (
	PendingStatus    MsgStatusType = "pending"
	RunningStatus    MsgStatusType = "running"
	SuccessStatus    MsgStatusType = "success"
	FailedStatus     MsgStatusType = "failed"
	SkippedStatus    MsgStatusType = "skipped"
	TerminatedStatus MsgStatusType = "terminated"

	CreatingStatus MsgStatusType = "creating"
	NormalStatus   MsgStatusType = "normal"
	StoppedStatus  MsgStatusType = "stopped"
	ScalingStatus  MsgStatusType = "scaling"
	DeletingStatus MsgStatusType = "deleting"
	DeletedStatus  MsgStatusType = "deleted"
)

var statusPastParticiples = map[MsgStatusType]string{
	SuccessStatus:    "succeeded",
	FailedStatus:     "failed",
	SkippedStatus:    "skipped",
	TerminatedStatus: "terminated",
}

type BaseMsg struct {
	Name   string
	Type   MsgKindType
	Status MsgStatusType

	HappenedAtMs uint64
}

type IDMsg struct {
	// Identification information
	AuthorID  uint64
	TenantID  uint64
	ProjectID uint64
	ClusterID uint64
}

type BackupMsg struct {
	BaseMsg
	IDMsg

	BackupID uint64
	Size     int

	BackupScheduleID uint64
	BucketID         uint64
}

type BackupExportMsg struct {
	BaseMsg
	IDMsg

	BackupExportID uint64
}

type RestoreMsg struct {
	BaseMsg
	IDMsg

	RestoreID   uint64
	LogBackupID uint64
	BackupID    uint64
}

func (msg *RestoreMsg) ConvertToDisplayEvent(displayStatus event.EventStatus) *event.DisplayEvent {
	data := BuildEventBasicInfos(msg.BackupID, msg.HappenedAtMs, msg.IDMsg)
	data.Summary = BuildDisplayEventSummary(msg.Name, msg.Type, msg.Status)
	data.DisplayEventType = string(entity.RestoreDisplayType)
	data.DisplayStatus = displayStatus
	data.Detail = msg
	return data
}

type ChangefeedMsg struct {
	BaseMsg
	IDMsg

	ChangefeedID             uint64
	CdcClusterID             uint64
	ChangefeedInstanceTypeID uint64
	DfPrivateLinkEndpointID  uint64
}

func BuildEventBasicInfos(
	taskID uint64,
	at uint64,
	ids IDMsg,
) *event.DisplayEvent {
	return BuildEventBasicInfosWithContextID(
		strconv.FormatUint(taskID, appconfig.DecimalBase), at, ids,
	)
}

// BuildEventBasicInfosWithContextID builds a DisplayEvent envelope with an arbitrary context id
// (e.g. Premium DM string task ids like "tsk_...").
func BuildEventBasicInfosWithContextID(
	contextID string,
	at uint64,
	ids IDMsg,
) *event.DisplayEvent {
	return &event.DisplayEvent{
		HappenedAtMs: at,
		AuthorID:     ids.AuthorID,
		TenantID:     ids.TenantID,
		ProjectID:    ids.ProjectID,
		ClusterID:    ids.ClusterID,
		ContextID:    contextID,
		Detail:       nil,
	}
}

// PremiumDMMsg is the Detail payload for Premium DM DisplayEvents.
type PremiumDMMsg struct {
	BaseMsg
	IDMsg

	MigrationId   string
	Mode          string
	ImportMode    string
	Stage         string
	OriginalError string
}

// ImportIntoMsg is the Detail payload for Import Into DisplayEvents (type ImportData).
type ImportIntoMsg struct {
	BaseMsg
	IDMsg

	ImportId      uint64
	OriginalError string
	TotalSize     uint64
}

// PrivateEndpointMsg is the Detail payload for Private Endpoint DisplayEvents.
type PrivateEndpointMsg struct {
	BaseMsg
	IDMsg

	EndpointId    uint64
	SharedPoolID  string
	ServiceName   string
	EndpointType  string
	OriginalError string
}

func BuildDisplayEventSummary(msgName string, msgType MsgKindType, msgStatus MsgStatusType) string {
	var summary string
	if msgStatus == PendingStatus {
		summary += fmt.Sprintf(brStartedMsg+"\n", msgType)
	} else if participle, ok := statusPastParticiples[msgStatus]; ok {
		summary += fmt.Sprintf(brBasicMsg+"\n", msgType,
			participle)
	} else {
		summary += fmt.Sprintf(brUnknownMsg+"\n", msgType)
	}

	summary += fmt.Sprintf(nameMsg, msgName)

	return summary
}

type ImportMsg struct {
	BaseMsg
	IDMsg

	ImportId             uint64
	OriginalError        string
	UserFacingError      string
	ComponentVersion     string
	TotalSize            int
	ProcessSize          int
	TotalTables          int
	PendingTables        int
	CurrentTables        int
	CompletedTables      int
	TaskStartedAt        string
	TaskImportingAt      string
	TaskPostProcessingAt string
}
