package resourcepool

import (
	"context"
	"errors"

	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/entity"
	"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 (s *serviceImpl) UpdateResourcePoolName(ctx context.Context,
	request *globalngv1.UpdateResourcePoolNameRequest) (*entity.ResourcePool, bizerr.BizError) {
	ctx, span := tracer.Start(ctx, "Domain.UpdateResourcePoolName")
	defer span.End()

	if request == nil {
		return nil, bizerr.New(bizerr.ErrCodeParams, "request cannot be nil")
	}

	if request.ResourcePoolId == 0 || request.Name == "" {
		return nil, bizerr.New(bizerr.ErrCodeParams, "request id and name cannot be empty")
	}

	resourcePool, err := s.resourcePoolRepo.Load(ctx, request.ResourcePoolId, false)
	if err != nil {
		return nil, err
	}
	if resourcePool == nil {
		return nil, bizerr.New(bizerr.ErrCodeRecordNotFound, "resource pool not found")
	}
	if lifecycleErr := servicecommon.RequireResourcePoolLifecycle(
		resourcePool,
		resourcepoolpolicy.OperationRenamePool,
	); lifecycleErr != nil {
		return nil, lifecycleErr
	}

	if request.GetValidateOnly() {
		resourcePool.Name = request.GetName()
		if namespaceErr := s.validateOrganizationNamespaceLocked(
			ctx,
			resourcePool.ResourcePool,
			resourcePool.GetId(),
			false,
		); namespaceErr != nil {
			return nil, namespaceErr
		}
		return resourcePool, nil
	}

	var updated *entity.ResourcePool
	transactionErr := s.transaction.Transaction(ctx, func(ctx context.Context) error {
		if usesOrganizationNameNamespace(resourcePool.ResourcePool) {
			if lockErr := s.resourcePoolRepo.LockOrganizationNamespace(ctx, resourcePool.GetOwnerId()); lockErr != nil {
				return bizerr.WrapError(lockErr, "lock organization resource pool namespace")
			}
		}

		locked, lockErr := s.resourcePoolRepo.LoadForUpdate(ctx, request.GetResourcePoolId(), false)
		if lockErr != nil {
			return lockErr
		}
		if locked == nil {
			return bizerr.New(bizerr.ErrCodeRecordNotFound, "resource pool not found")
		}
		if lifecycleErr := servicecommon.RequireResourcePoolLifecycle(
			locked,
			resourcepoolpolicy.OperationRenamePool,
		); lifecycleErr != nil {
			return lifecycleErr
		}
		if locked.GetOwnerType() != resourcePool.GetOwnerType() ||
			locked.GetOwnerId() != resourcePool.GetOwnerId() ||
			locked.GetServicePlan() != resourcePool.GetServicePlan() {
			return bizerr.New(bizerr.ErrCodeUnknown, "resource pool namespace changed during rename")
		}

		locked.Name = request.GetName()
		if namespaceErr := s.validateOrganizationNamespaceLocked(
			ctx,
			locked.ResourcePool,
			locked.GetId(),
			false,
		); namespaceErr != nil {
			return namespaceErr
		}
		updated = locked
		if saveErr := s.resourcePoolRepo.Save(ctx, locked); saveErr != nil {
			return bizerr.WrapError(saveErr, "save resource pool name")
		}
		return nil
	})
	if transactionErr != nil {
		var businessErr bizerr.BizError
		if errors.As(transactionErr, &businessErr) {
			return nil, businessErr
		}
		return nil, bizerr.WrapGormError(transactionErr, "update resource pool name")
	}

	return updated, nil
}
