package action

import (
	"strconv"

	"github.com/tidbcloud/fastflow/pkg/entity/run"
	regionaldedicatedv1 "github.com/tidbcloud/infra-provider/api/tidbcloud/regional-server/v1"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/adapter/eventbus"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/adapter/regionserver"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/entity"
	clusterrepo "github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/repository/cluster"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/repository/region"
	"github.com/tidbcloud/tidb-management-service/dedicated-global-service/domain/service/workflow/common"
	"github.com/tidbcloud/tidb-management-service/utilities/clusterevent"
	"github.com/tidbcloud/tidb-management-service/utilities/workflow"
)

const (
	PauseCluster = "pause_cluster"
)

type PauseClusterAction struct {
	regionalCli regionserver.Client
	clusterRepo clusterrepo.Repo
	regionRepo  region.Repo
	committer   eventbus.WALCommitter
}

func NewPauseClusterAction(
	regionalCli regionserver.Client,
	clusterRepo clusterrepo.Repo,
	regionRepo region.Repo,
	committer eventbus.WALCommitter,
) *PauseClusterAction {
	return &PauseClusterAction{
		regionalCli: regionalCli,
		clusterRepo: clusterRepo,
		regionRepo:  regionRepo,
		committer:   committer,
	}
}

func (a *PauseClusterAction) Name() string {
	return PauseCluster
}

func (a *PauseClusterAction) ParameterNew() any {
	return &common.ClusterIdParameter{}
}

func (a *PauseClusterAction) Run(ctx run.ExecuteContext, params any) error {
	cctx, span := workflow.GenerateContext(ctx)

	clusterId, err := common.GetClusterId(params)
	if err != nil {
		tilog.Error(cctx, "failed to get cluster id", zap.Error(err))
		return err
	}

	tilog.Info(cctx, "start to pause cluster", zap.Uint64("cluster_id", clusterId))
	defer func() {
		tilog.Info(cctx, "end to pause cluster", zap.Uint64("cluster_id", clusterId))
		span.End()
	}()

	cluster, err := a.clusterRepo.Get(cctx, clusterId, false)
	if err != nil {
		tilog.Error(cctx, "failed to get cluster", zap.Error(err))
		return err
	}

	regionEntity, err := a.regionRepo.SelectRegionById(cctx, cluster.RegionId, cluster.GetOrganizationId())
	if err != nil {
		tilog.Error(cctx, "failed to find region", zap.Error(err))
		return err
	}

	pauseReq := &regionaldedicatedv1.PauseClusterRequest{
		ClusterId: strconv.FormatUint(cluster.ClusterId, 10),
	}

	if _, err := a.regionalCli.PauseCluster(cctx, regionEntity, pauseReq); err != nil {
		tilog.Error(cctx, "failed to pause cluster", zap.Error(err))
		return err
	}

	// send event
	ev := entity.NewClusterEventBuilder(cctx, cluster, clusterevent.EventTypePausing).Build()
	if err := a.committer.Write(cctx, clusterevent.TopicClusterEvent, ev); err != nil {
		return err
	}

	return nil
}
