package center

import (
	"fmt"
	"strconv"

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

var (
	brStartedMsg = "The %s task was started , it is in a pending state."
	brRunningMsg = "The %s task started to run."
	brBasicMsg   = "The %s task was %s."

	nameMsg = "Task name: %s."
)

const FinalBackupName = "final-backup"

type MsgKindType string

const (
	AutoBackup   MsgKindType = "auto-backup"
	FinalBackup  MsgKindType = "final-backup"
	LogBackup    MsgKindType = "log-backup"
	ManualBackup MsgKindType = "manual-backup"

	VolumeRestore MsgKindType = "volume-restore"
	NormalRestore MsgKindType = "snapshot-restore"
	PiTRRestore   MsgKindType = "pointInTime-restore"

	BackupExport MsgKindType = "backup-export"

	MysqlChangefeed          MsgKindType = "mysql"
	KafkaChangefeed          MsgKindType = "kafka"
	TiDBChangefeed           MsgKindType = "tidb"
	ServerlessTiDBChangefeed MsgKindType = "serverless_tidb"
)

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"
	StoppingStatus MsgStatusType = "stopping"
	StoppedStatus  MsgStatusType = "stopped"
	EditingStatus  MsgStatusType = "editing"
	StartingStatus MsgStatusType = "starting"
	ScalingStatus  MsgStatusType = "scaling"
	ErrorStatus    MsgStatusType = "error"
	DeletingStatus MsgStatusType = "deleting"
	DeletedStatus  MsgStatusType = "deleted"
)

var MsgStatus2EventMap = map[MsgStatusType]event.EventStatus{
	PendingStatus:    event.EventStatusStarted,
	RunningStatus:    event.EventStatusRunning,
	SuccessStatus:    event.EventStatusSucceeded,
	FailedStatus:     event.EventStatusFailed,
	SkippedStatus:    event.EventStatusSkipped,
	TerminatedStatus: event.EventStatusCanceled,
}

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() *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 = MsgStatus2EventMap[msg.Status]
	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 &event.DisplayEvent{
		HappenedAtMs: at,
		AuthorID:     ids.AuthorID,
		TenantID:     ids.TenantID,
		ProjectID:    ids.ProjectID,
		ClusterID:    ids.ClusterID,
		ContextID:    strconv.FormatUint(taskID, appconfig.DecimalBase),
		Detail:       nil,
	}
}

func BuildDisplayEventSummary(msgName string, msgType MsgKindType, msgStatus MsgStatusType) string {
	var (
		summary       string
		displayStatus event.EventStatus
	)

	if s, ok := MsgStatus2EventMap[msgStatus]; ok {
		displayStatus = s
	} else {
		displayStatus = event.EventStatusRunning
	}

	switch displayStatus {
	case event.EventStatusStarted:
		summary += fmt.Sprintf(brStartedMsg+"\n", msgType)
	case event.EventStatusRunning:
		summary += fmt.Sprintf(brRunningMsg+"\n", msgType)
	default:
		summary += fmt.Sprintf(brBasicMsg+"\n", msgType,
			statusPastParticiples[msgStatus])
	}

	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
}
