package clusteraction

import (
	"context"
	"fmt"

	"github.com/tidbcloud/core-svc/idl/pbgen/proto/core"
	opent "github.com/tidbcloud/devops/entity/operation"
	"github.com/tidbcloud/devops/pkg/service/operation/actions"
	mgmtv1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"
)

var (
	ActionScaleClusterPdComponent opent.ActionMetadata = opent.ActionMetadata{
		Name: "ScaleClusterPdComponent",
		Type: opent.ActionTypeAuto,
	}
)

type scaleClusterPdComponent struct {
	actions.BaseAction
	comps *actions.Components
}

func NewScaleClusterPdComponent(comps *actions.Components) actions.AutoAction {
	return &scaleClusterPdComponent{comps: comps}
}

func (a *scaleClusterPdComponent) Metadata() opent.ActionMetadata {
	return ActionScaleClusterPdComponent
}

func (a *scaleClusterPdComponent) PreCheck(ctx context.Context, instance *opent.Instance) error {
	_, err := a.getParam(ctx, instance)
	if err != nil {
		return err
	}

	cid, err := actions.GetClusterID(instance)
	if err != nil {
		return err
	}

	_, err = a.comps.CoreSvc.GetCluster(ctx, cid, false)
	if err != nil {
		return err
	}

	return nil
}

func (a *scaleClusterPdComponent) Start(ctx context.Context, instance *opent.Instance) (*actions.ActionResult, error) {
	req, err := a.getParam(ctx, instance)
	if err != nil {
		return actions.FailedActionResult(err), nil
	}
	_, err = a.comps.CoreSvc.Mgmt.Cluster.ScaleClusterPdComponent(ctx, req)
	if err != nil {
		return actions.FailedActionResult(err), nil
	}

	return actions.RunningActionResult("sent request to scale cluster pd", nil), nil
}

func (a *scaleClusterPdComponent) Result(ctx context.Context, instance *opent.Instance) (*actions.ActionResult, error) {
	cid, err := actions.GetClusterID(instance)
	if err != nil {
		return nil, err
	}

	cluster, err := a.comps.CoreSvc.GetCluster(ctx, cid, false)
	if err != nil {
		return actions.NewActionResult(opent.ActionStatusUnknown, err.Error(), nil), nil
	}

	if cluster.Status == core.ClusterStatus_CLUSTER_STATUS_NORMAL {
		return actions.SucceededActionResult(nil), nil
	}

	return actions.RunningActionResult(fmt.Sprintf("cluster status is '%s'", cluster.Status), nil), nil
}

func (a *scaleClusterPdComponent) getParam(ctx context.Context, instance *opent.Instance) (*mgmtv1.ScaleClusterPdComponentRequest, error) {
	cid, err := actions.GetClusterID(instance)
	if err != nil {
		return nil, err
	}
	cluster, err := a.comps.CoreSvc.GetCluster(ctx, cid, false)
	if err != nil {
		return nil, err
	}

	newArch := false
	if cluster.Attributes != nil && cluster.Attributes.UseNewDedicatedArch != nil {
		newArch = *cluster.Attributes.UseNewDedicatedArch
	}
	if !newArch {
		return nil, fmt.Errorf("only 3-layer cluster supported")
	}
	nodeSize, _ := instance.GetParam(opent.ParamNodeSize)
	if nodeSize == "" {
		return nil, fmt.Errorf("scale param node_size is required")
	}

	req := &mgmtv1.ScaleClusterPdComponentRequest{
		ClusterId: cid,
		SpuName:   nodeSize,
	}

	return req, nil
}
