package userbehavior

import (
	"context"
	"fmt"
	"strings"
	"time"

	"github.com/expr-lang/expr"
	larkcard "github.com/larksuite/oapi-sdk-go/v3/card"
	ubent "github.com/tidbcloud/devops/entity/userbehavior"
	mgmtevent "github.com/tidbcloud/tidb-management-service/utilities/clusterevent"
)

type clusterUBEvent struct {
	originEv                 *mgmtevent.ClusterEvent
	tenantName               *string
	tenantID                 uint64
	tenantAlias              *string
	bizRegion                *string
	clusterID                uint64
	clusterName              *string
	clusterBehaviorPredicate *string
	extraInfo                string
}

var clusterEventParams = []string{
	"tenant_id",
	"tenant_name",
	"biz_region",
	"cluster_id",
	"cluster_name",
	"cluster_type",
	"cluster_behavior_type",
}

var acceptedClusterEvents = []mgmtevent.EventType{
	mgmtevent.EventTypeCreated,
	mgmtevent.EventTypeRestored,
	mgmtevent.EventTypePaused,
	mgmtevent.EventTypeResumed,
	mgmtevent.EventTypeScaling, // currently topo info is only available for ClusterScaling events.
	mgmtevent.EventTypeScaled,
	mgmtevent.EventTypeDeleted,
	mgmtevent.EventTypeCleared,
	mgmtevent.EventTypeVolumeSnapshotRestored,
}

func (clusterEvent *clusterUBEvent) HandleUBEvent(ctx context.Context) error {
	return nil
}

func (clusterEvent *clusterUBEvent) PreProcess(ctx context.Context) error {
	return nil
}

func (clusterEvent *clusterUBEvent) PostProcess(ctx context.Context) error {
	return nil
}

func (clusterEvent *clusterUBEvent) ProcessTemplate(ctx context.Context, template string) (string, error) {
	return template, nil
}

func (clusterEvent *clusterUBEvent) DefaultText(ctx context.Context) string {
	var tenantName, tenantAlias string
	if clusterEvent.tenantName != nil {
		tenantName = *clusterEvent.tenantName
	}
	if clusterEvent.tenantAlias != nil {
		tenantAlias = *clusterEvent.tenantAlias
	}

	var clusterType string
	if clusterEvent.originEv.IsDevTier {
		clusterType = "Shared"
	} else {
		clusterType = "Dedicated"
	}

	return fmt.Sprintf("[** %s **] Tenant** %s **(%d, alias: %s) ** %s ** a %s cluster** %s **(%d).\n**Event Time:** %s\n%s",
		*clusterEvent.bizRegion,
		tenantName,
		clusterEvent.tenantID,
		tenantAlias,
		*clusterEvent.clusterBehaviorPredicate,
		clusterType,
		*clusterEvent.clusterName,
		clusterEvent.clusterID,
		formatClusterEventTime(clusterEvent.originEv.EventCreatedAtMs),
		clusterEvent.extraInfo,
	)
}

func formatClusterEventTime(eventCreatedAtMs int64) string {
	if eventCreatedAtMs <= 0 {
		return "unknown"
	}
	return time.UnixMilli(eventCreatedAtMs).UTC().Format(time.RFC3339)
}

func (clusterEvent *clusterUBEvent) GetAvailableParams(ctx context.Context) []string {
	return clusterEventParams
}

func (clusterEvent *clusterUBEvent) GetUBEventType() ubent.UBEventTp {
	return ubent.UBEventCluster
}

func (event *clusterUBEvent) CustomFilter(ctx context.Context, textFilter string) (ret bool, err error) {
	program, err := expr.Compile(textFilter)
	if err != nil {
		return ret, err
	}

	output, err := expr.Run(program, event.originEv)
	if err != nil {
		return ret, err
	}
	ret, ok := output.(bool)
	if !ok {
		return ret, fmt.Errorf("not return a bool type")
	}

	return ret, nil
}

func newClusterUBEvent(ev *mgmtevent.ClusterEvent) UBEvent {
	ubEvent := clusterUBEvent{
		originEv:                 ev,
		tenantName:               nil,
		tenantAlias:              nil,
		bizRegion:                nil,
		tenantID:                 ev.TenantID,
		clusterID:                ev.ClusterID,
		clusterBehaviorPredicate: cvtToPredicate(ev.EventType),
	}
	return &ubEvent
}

func cvtToPredicate(eventType mgmtevent.EventType) *string {
	str := string(eventType)
	result := strings.ToLower(strings.Replace(str, "Cluster", "", 1))
	return &result
}

func (e *clusterUBEvent) BuildCustomCard(ctx context.Context) (*larkcard.MessageCard, error) {
	return nil, nil // Use standard card
}
