package action

import (
	"context"
	"strconv"

	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/entity"
	clusterrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/cluster"
	resourcepoolrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/resourcepool"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/resourcepoolpolicy"
	servicecommon "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/common"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func guardClusterResourcePoolMutation(
	ctx context.Context,
	clusterRepo clusterrepo.Repo,
	resourcePoolRepo resourcepoolrepo.Repo,
	cluster *entity.Cluster,
	operation resourcepoolpolicy.Operation,
) (bool, error) {
	return guardClusterResourcePoolMutationByID(ctx, clusterRepo, resourcePoolRepo, cluster.GetClusterId(), operation)
}

func guardClusterResourcePoolMutationByID(
	ctx context.Context,
	clusterRepo clusterrepo.Repo,
	resourcePoolRepo resourcepoolrepo.Repo,
	clusterID uint64,
	operation resourcepoolpolicy.Operation,
) (bool, error) {
	latestCluster, berr := clusterRepo.Get(ctx, clusterID, true)
	if berr != nil {
		return false, berr
	}
	if latestCluster.GetDeleteTime() != nil {
		return true, nil
	}
	return guardLoadedClusterResourcePoolMutation(ctx, resourcePoolRepo, latestCluster, operation)
}

func guardLoadedClusterResourcePoolMutation(
	ctx context.Context,
	resourcePoolRepo resourcepoolrepo.Repo,
	cluster *entity.Cluster,
	operation resourcepoolpolicy.Operation,
) (bool, error) {
	resourcePoolID, err := strconv.ParseUint(cluster.GetSharedPoolId(), 10, 64)
	if err != nil || resourcePoolID == 0 {
		return false, bizerr.New(bizerr.ErrCodeUnknown, "cluster has an invalid resource pool id")
	}
	resourcePool, berr := resourcePoolRepo.Load(ctx, resourcePoolID, true)
	if berr != nil {
		return false, berr
	}
	if resourcePool.GetDeleteTime() != nil {
		return true, nil
	}
	if lifecycleErr := servicecommon.RequireResourcePoolLifecycle(
		resourcePool,
		operation,
	); lifecycleErr != nil {
		return false, lifecycleErr
	}
	return false, nil
}

func guardResourcePoolMutation(
	ctx context.Context,
	resourcePoolRepo resourcepoolrepo.Repo,
	resourcePoolID uint64,
	operation resourcepoolpolicy.Operation,
) (bool, error) {
	resourcePool, berr := resourcePoolRepo.Load(ctx, resourcePoolID, true)
	if berr != nil {
		return false, berr
	}
	if resourcePool.GetDeleteTime() != nil {
		return true, nil
	}
	if lifecycleErr := servicecommon.RequireResourcePoolLifecycle(
		resourcePool,
		operation,
	); lifecycleErr != nil {
		return false, lifecycleErr
	}
	return false, nil
}
