package ngoperation

import (
	"context"
	"fmt"

	clusterng "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	opent "github.com/tidbcloud/devops/entity/operation"
	"github.com/tidbcloud/devops/pkg/infra/clients/mgmthttpcli"
	"github.com/tidbcloud/devops/pkg/service/operation/actions"
	nextgenv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
)

var (
	ActionDeleteTiKVGroup = opent.ActionMetadata{
		Name: "DeleteTiKVGroup",
		Type: opent.ActionTypeAuto,
	}
)

var _ actions.Action = &deleteTiKVGroup{}

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

func NewDeleteTiKVGroup(comps *actions.Components) actions.AutoAction {
	return &deleteTiKVGroup{comps: comps}
}

func (a *deleteTiKVGroup) Metadata() opent.ActionMetadata {
	return ActionDeleteTiKVGroup
}

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

func (a *deleteTiKVGroup) Start(ctx context.Context, instance *opent.Instance) (*actions.ActionResult, error) {
	req, rp, err := a.getParam(ctx, instance)
	if err != nil {
		return actions.FailedActionResult(err), nil
	}

	logicalRegion, provider := GetLogicalRegionAndProviderString(rp.GetRegion())
	err = a.comps.MgmtHTTP.NextGenRegionServer(logicalRegion, provider).DeleteTiKVGroup(ctx, req)
	if err != nil {
		return actions.FailedActionResult(err), nil
	}

	return actions.RunningActionResult(fmt.Sprintf("sent request to delete TiKV group: %s", req.GetTikvGroupId()), nil), nil
}

func (a *deleteTiKVGroup) Result(ctx context.Context, instance *opent.Instance) (*actions.ActionResult, error) {
	sharedPoolID, tikvGroupID, err := getDeleteTiKVGroupRequiredParam(instance)
	if err != nil {
		return nil, err
	}

	_, sp, err := GetResourcePoolAndSharedPoolWithRetry(ctx, sharedPoolID, a.comps.CoreSvc, a.comps.MgmtHTTP, 3)
	if err != nil {
		return actions.NewActionResult(opent.ActionStatusUnknown, err.Error(), nil), nil
	}
	if sp == nil {
		return actions.NewActionResult(opent.ActionStatusUnknown, "shared pool is nil", nil), nil
	}

	if comp := findTiKVGroup(sp, tikvGroupID); comp != nil {
		return actions.RunningActionResult(fmt.Sprintf("TiKV group still exists with phase '%s'", comp.Phase), nil), nil
	}

	return actions.SucceededActionResult(nil), nil
}

func (a *deleteTiKVGroup) getParam(ctx context.Context, instance *opent.Instance) (*mgmthttpcli.DeleteTiKVGroupRequest, *nextgenv1.ResourcePoolProfile, error) {
	req, err := buildDeleteTiKVGroupParam(instance)
	if err != nil {
		return nil, nil, err
	}

	rp, err := a.comps.CoreSvc.Mgmt.GetResourcePoolString(ctx, req.GetSharedPoolId())
	if err != nil {
		return nil, nil, err
	}

	return req, rp, nil
}

func buildDeleteTiKVGroupParam(instance *opent.Instance) (*mgmthttpcli.DeleteTiKVGroupRequest, error) {
	sharedPoolID, tikvGroupID, err := getDeleteTiKVGroupRequiredParam(instance)
	if err != nil {
		return nil, err
	}

	return &mgmthttpcli.DeleteTiKVGroupRequest{
		SharedPoolId: sharedPoolID,
		TikvGroupId:  tikvGroupID,
	}, nil
}

func getDeleteTiKVGroupRequiredParam(instance *opent.Instance) (string, string, error) {
	sharedPoolID, err := actions.GetResourcePoolID(instance)
	if err != nil {
		return "", "", err
	}

	tikvGroupID, ok := instance.GetParam(opent.ParamTiKVGroupID)
	if !ok || tikvGroupID == "" {
		return "", "", fmt.Errorf("param tikv_group_id is required")
	}

	return sharedPoolID, tikvGroupID, nil
}

func findTiKVGroup(sp *mgmthttpcli.SharedPool, tikvGroupID string) *mgmthttpcli.Component {
	if sp == nil {
		return nil
	}
	for _, comp := range sp.ComponentGroups {
		if comp.Id == tikvGroupID && componentTypeEqual(comp.ComponentType, clusterng.ComponentType_TIKV.String()) {
			return comp
		}
	}
	return nil
}
