package action

import (
	"strconv"
	"strings"

	clusterngv1beta "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	"github.com/tidbcloud/fastflow/pkg/entity/run"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/regionalserver"
	clusterrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/cluster"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/region"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/workflow/common"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/workflow"
)

const (
	FullClusterInfo = "full_cluster_info"
)

type FullClusterInfoAction struct {
	regionalCli regionalserver.Client
	clusterRepo clusterrepo.Repo
	regionRepo  region.Repo
}

func NewFullClusterInfoAction(
	regionalCli regionalserver.Client,
	clusterRepo clusterrepo.Repo,
	regionRepo region.Repo,
) *FullClusterInfoAction {
	return &FullClusterInfoAction{
		regionalCli: regionalCli,
		clusterRepo: clusterRepo,
		regionRepo:  regionRepo,
	}
}

func (p *FullClusterInfoAction) Name() string {
	return FullClusterInfo
}

func (p *FullClusterInfoAction) ParameterNew() any {
	return &common.ClusterIdParameter{}
}

func (p *FullClusterInfoAction) 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
	}
	tidbGroupIdsStr, ok := ctx.GetVar(common.KeyTidbGroupIds)
	if !ok {
		tilog.Error(cctx, "not found the tidbgroup ids", zap.String("tidb_group_ids", tidbGroupIdsStr))
		return bizerr.New(bizerr.ErrCodeRecordNotFound, "not found the tidbgroup ids")
	}

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

	if v, ok := ctx.GetVar(common.KeySkipWaitAvailable); ok && v == SkipWaitavailable {
		tilog.Info(cctx, "skip wait available action")
		return nil
	}
	if tidbGroupIdsStr == "" {
		tilog.Warn(cctx, "no tidbgroup ids to poll")
		return nil
	}

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

	tidbgroupIds := strings.Split(tidbGroupIdsStr, ",")
	if len(tidbgroupIds) == 0 {
		tilog.Warn(cctx, "no tidbgroup ids to poll")
		return nil
	}

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

	regionTidbGroup, err := p.regionalCli.GetTidbGroup(cctx, regionEntity, &clusterngv1beta.GetTiDBGroupRequest{
		ClusterId:   strconv.FormatUint(cluster.ClusterId, 10),
		TidbGroupId: tidbgroupIds[0],
	})
	if err != nil {
		tilog.Error(cctx, "failed to get cluster", zap.Error(err))
		return err
	}

	cluster.Version = regionTidbGroup.GetVersion()

	return p.clusterRepo.Save(cctx, cluster)
}
