package cluster_svc

import (
	"context"
	"fmt"
	"time"

	"github.com/lithammer/shortuuid/v3"
	"github.com/tidbcloud/eventbus-datastruct/event"
	"github.com/tidbcloud/pkgv2/log"
	"github.com/tidbcloud/serverless-service/internal/config"
	"github.com/tidbcloud/serverless-service/internal/domain/constant"
	"github.com/tidbcloud/serverless-service/internal/domain/facade"
	"github.com/tidbcloud/serverless-service/internal/infra/eventbus"
	tidbmgmtservicev1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"
	"github.com/tidbcloud/tiinf/transport/tieventbus"
	"go.uber.org/zap"
)

type ServicePlanEventService struct {
	accountFacade   facade.AccountFacade
	mgmtFacade      facade.MgmtSvcFacade
	o11yFacade      facade.O11yFacade
	eventbusService *eventbus.EventbusService
}

func NewServicePlanEventService(
	accountFacade facade.AccountFacade,
	mgmtFacade facade.MgmtSvcFacade,
	o11yFacade facade.O11yFacade,
	eventbusService *eventbus.EventbusService,
) *ServicePlanEventService {
	return &ServicePlanEventService{
		accountFacade:   accountFacade,
		mgmtFacade:      mgmtFacade,
		o11yFacade:      o11yFacade,
		eventbusService: eventbusService,
	}
}

func (s *ServicePlanEventService) Execute(ctx context.Context) error {
	if config.IsLocalStage() {
		return nil
	}
	logger := log.WithContextL(ctx).With(zap.String("job", "ServicePlanEventService"))
	logger.Info("Execution Start")

	for _, cfg := range config.Global().WorkerConfig.RegionalConfig {
		for _, k8sCfg := range cfg.K8sConfig {
			res, err := s.o11yFacade.GetProvisionedRCU(ctx, k8sCfg.O11yUrl)
			if err != nil {
				logger.Error("failed to get o11y provisioned RCU metrics", zap.Error(err))
				continue
			}
			logger.Info(
				"get o11y provisioned RCU metrics success",
				zap.Any("result", res),
				zap.String("region", cfg.Region),
				zap.Any("kubernetes", k8sCfg.Kubernetes),
			)
			for clusterId, provisionedRCU := range res {
				if config.Global().ServerConfig.Stage == config.StageProd && provisionedRCU <= 2000 {
					continue
				}
				cluster, err := s.mgmtFacade.GetCluster(
					ctx,
					clusterId,
					tidbmgmtservicev1.ClusterFilter_CLUSTER_VIEW_BASIC,
				)
				if err != nil {
					logger.Error("failed to get cluster", zap.Error(err), zap.Uint64("cluster_id", clusterId))
					continue
				}
				if uint64(cluster.GetServerlessCluster().GetCluster().GetAutoScaling().GetMaxRcu()) <= provisionedRCU {
					logger.Info("cluster RCU provisioned exceeds maxRCU, publish event",
						zap.Uint64("cluster_id", cluster.ClusterId),
						zap.Uint32("maxRCU", cluster.GetServerlessCluster().GetCluster().GetAutoScaling().GetMaxRcu()),
						zap.Uint32("provisionedRCU", uint32(provisionedRCU)),
					)
					if err := s.eventbusService.Publish(&tieventbus.Event{
						ID:   shortuuid.New(),
						Type: event.DisplayEventTopic,
						Data: event.DisplayEvent{
							DisplayEventType: constant.EventTypeResourceLimitation,
							DisplayStatus:    event.EventStatusSucceeded,
							Severity:         event.EventSeverityInfo,
							Summary:          constant.EventSummaryRCURestriction,
							HappenedAtMs:     uint64(time.Now().UTC().UnixMilli()),
							AuthorID:         0,
							ClusterID:        cluster.ClusterId,
							ProjectID:        cluster.ProjectId,
							TenantID:         cluster.OrganizationId,
							Detail: fmt.Sprintf("minRCU: %d, maxRCU: %d, provisionedRCU:%d",
								cluster.GetServerlessCluster().GetCluster().GetAutoScaling().GetMinRcu(),
								cluster.GetServerlessCluster().GetCluster().GetAutoScaling().GetMaxRcu(),
								provisionedRCU),
						},
					}); err != nil {
						logger.Error("failed to publish events center", zap.Error(err))
					}
				}
			}
		}
	}

	logger.Info("Execution End")
	return nil
}
