package action

import (
	"errors"
	"strconv"

	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/eventbus"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/regionalserver"
	regionrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/region"
	resourcepoolrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/resourcepool"
	"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 (
	DeleteResourcePool = "delete_resource_pool"
)

type DeleteResourcePoolAction struct {
	regionalCli      regionalserver.Client
	resourcePoolRepo resourcepoolrepo.Repo
	regionRepo       regionrepo.Repo
	eventCommitter   eventbus.WALCommitter
	metadataHelper   *PremiumReservedMetadataHelper
}

func NewDeleteResourcePoolAction(
	regionalCli regionalserver.Client,
	resourcePoolRepo resourcepoolrepo.Repo,
	regionRepo regionrepo.Repo,
	eventCommitter eventbus.WALCommitter,
	metadataHelper *PremiumReservedMetadataHelper,
) *DeleteResourcePoolAction {
	return &DeleteResourcePoolAction{
		regionalCli:      regionalCli,
		resourcePoolRepo: resourcePoolRepo,
		regionRepo:       regionRepo,
		eventCommitter:   eventCommitter,
		metadataHelper:   metadataHelper,
	}
}

func (p *DeleteResourcePoolAction) Name() string {
	return DeleteResourcePool
}

func (p *DeleteResourcePoolAction) ParameterNew() any {
	return &common.ResourcePoolParameter{}
}

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

	resourcePoolId, err := common.GetResourcePoolId(params)
	if err != nil {
		tilog.Error(cctx, "failed to delete resource pool", zap.Error(err))
		return err
	}

	tilog.Info(cctx, "start to delete resource pool", zap.Uint64("resource_pool_id", resourcePoolId))
	defer func() {
		tilog.Info(cctx, "end to delete resource pool", zap.Uint64("resource_pool_id", resourcePoolId))
		span.End()
	}()

	rp, err := p.resourcePoolRepo.Load(cctx, resourcePoolId, true)
	if err != nil {
		tilog.Error(cctx, "failed to load deleted resource pool", zap.Error(err))
		return err
	}
	if rp.GetDeleteTime() == nil {
		err := errors.New("resource pool delete ownership is missing")
		tilog.Error(cctx, "refuse to delete live resource pool", zap.Error(err))
		return err
	}

	region, err := p.regionRepo.Get(cctx, rp.RegionId)
	if err != nil {
		tilog.Error(cctx, "failed to get region",
			zap.Uint64("region_id", rp.RegionId),
			zap.Error(err))
		return err
	}

	deleteErr := p.regionalCli.DeleteSharedPool(cctx, region, &clusterngv1beta.DeleteSharedPoolRequest{
		SharedPoolId:   strconv.FormatUint(resourcePoolId, 10),
		PruneDataplane: true,
	})
	if deleteErr != nil && deleteErr.ErrCode() != bizerr.ErrCodeRecordNotFound {
		tilog.Error(cctx, "failed to delete shared pool in regional",
			zap.Uint64("resource_pool_id", resourcePoolId),
			zap.Error(deleteErr),
		)
		return deleteErr
	}
	if berr := p.metadataHelper.writeDeleteMetadataByResourcePoolID(cctx, resourcePoolId); berr != nil {
		tilog.Error(cctx, "failed to write premium reserved metadata after delete resource pool",
			zap.Uint64("resource_pool_id", resourcePoolId),
			zap.Error(berr),
		)
		return berr
	}

	return nil
}
