package action

import (
	"context"
	"fmt"

	"github.com/pingcap/tidb-operator/api/v2/core/v1alpha1"
	apiv1 "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	"github.com/tidbcloud/cluster-service-ng/domain/entity"
	"github.com/tidbcloud/cluster-service-ng/domain/workflow"
	"github.com/tidbcloud/cluster-service-ng/pkg/dataplane"
	"github.com/tidbcloud/cluster-service-ng/pkg/runtime/actions"
	"github.com/tidbcloud/cluster-service-ng/pkg/utils"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

const WaitTiKVGroupGoneActionName = "wait-tikv-group-gone"

type WaitTiKVGroupGoneAction struct {
	dataplaneManager dataplane.Manager
}

func NewWaitTiKVGroupGoneAction(dataplaneManager dataplane.Manager) actions.AsyncAction {
	return &WaitTiKVGroupGoneAction{
		dataplaneManager: dataplaneManager,
	}
}

func (a *WaitTiKVGroupGoneAction) Name() string {
	return WaitTiKVGroupGoneActionName
}

func (a *WaitTiKVGroupGoneAction) Start(args actions.ActionArgs) error {
	return nil
}

func (a *WaitTiKVGroupGoneAction) CheckFinish(args actions.ActionArgs) (bool, error) {
	ctx := utils.GenerateContext(args)
	tilog.Info(ctx, "check tikv group gone")

	sharedPool, err := deleteComponentTargetSharedPool(args)
	if err != nil {
		return false, err
	}

	remoteCli, err := a.dataplaneManager.GetClient(sharedPool.GetDataplaneName())
	if err != nil {
		return false, fmt.Errorf("failed to get remote client: %w", err)
	}

	for _, comp := range sharedPool.GetComponentGroups() {
		if comp.GetComponentType() != apiv1.ComponentType_TIKV || !workflow.CheckIsTargetComponent(ctx, comp, args) {
			continue
		}
		gone, err := a.checkTiKVGroupGone(ctx, remoteCli, sharedPool, comp)
		if err != nil || !gone {
			return gone, err
		}
	}
	return true, nil
}

func (a *WaitTiKVGroupGoneAction) checkTiKVGroupGone(
	ctx context.Context,
	remoteCli client.Client,
	sharedPool *entity.SharedPool,
	comp *entity.Component,
) (bool, error) {
	groupName := entity.GetComponentGroupName(comp)
	namespace := entity.GetDataPlaneNamespace(sharedPool.GetId())

	tikvGroup := &v1alpha1.TiKVGroup{}
	err := remoteCli.Get(ctx, client.ObjectKey{Name: groupName, Namespace: namespace}, tikvGroup)
	if err != nil {
		if apierrors.IsNotFound(err) {
			tilog.Info(ctx, "tikv group is gone", zap.String("groupName", groupName))
			return true, nil
		}
		return false, fmt.Errorf("failed to get tikv group %s/%s: %w", namespace, groupName, err)
	}

	tilog.Info(ctx, "tikv group still exists",
		zap.String("groupName", groupName),
		zap.Int32("replicas", tikvGroup.Status.Replicas))
	return false, nil
}
