package resourcepool

import (
	"context"

	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	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/repository/region"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/clusterevent"
)

func (s *serviceImpl) UpdateOrgDefaultResourcePool(ctx context.Context,
	request *globalngv1.UpdateOrgDefaultResourcePoolRequest) (*entity.ResourcePoolStrategy, bizerr.BizError) {
	ctx, span := tracer.Start(ctx, "Domain.UpdateOrgDefaultResourcePool")
	defer span.End()

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

	// load resource pool to make sure it exists
	resourcePool, err := s.resourcePoolRepo.Load(ctx, request.Strategy.DefaultResourcePoolId, false)
	if err != nil {
		tilog.Error(ctx, "failed to load resource pool", zap.Error(err))
		return nil, err
	}

	// Essential_V2 shared pools are platform-owned (OwnerType=SHARED, OwnerId=0).
	// They can be set as org default or global default (organization_id=0),
	// so the ownership check is skipped for this plan. For all other plans,
	// verify the pool belongs to the requesting organization.
	if resourcePool.ServicePlan != globalcommonv1.ServicePlan_Essential_V2 &&
		(resourcePool.OwnerType != globalngv1.ResourcePool_ORGANIZATION ||
			resourcePool.OwnerId != request.Strategy.OrganizationId) {
		tilog.Error(ctx, "resource pool does not belong to the organization",
			zap.Uint64("resourcePoolId", resourcePool.Id),
			zap.Uint64("ownerId", resourcePool.OwnerId),
			zap.Int("ownerType", int(resourcePool.OwnerType)),
			zap.Uint64("orgId", request.Strategy.OrganizationId),
		)
		return nil, bizerr.New(bizerr.ErrCodeParams, "resource pool does not belong to the organization")
	}

	cloudRegion, err := s.regionRepo.SelectRegion(ctx, region.Filter{
		CloudProvider: resourcePool.ProviderId,
		RegionId:      resourcePool.ResourcePool.RegionId,
		TenantId:      resourcePoolTenantId(resourcePool.ResourcePool),
		ServicePlan:   resourcePool.ServicePlan,
	})
	if err != nil {
		tilog.Error(ctx, "failed to get region", zap.Error(err))
		return nil, err
	}

	tenantId := request.Strategy.OrganizationId
	if resourcePool.ServicePlan != globalcommonv1.ServicePlan_Essential_V2 {
		tenantId = resourcePool.OwnerId
	}

	strategy, err := s.upsertDefaultResourcePool(
		ctx,
		cloudRegion,
		tenantId,
		resourcePool.Id,
		resourcePool.ServicePlan,
	)
	if err != nil {
		tilog.Error(ctx, "failed to upsert default resource pool", zap.Error(err))
		return nil, err
	}

	ev, evErr := entity.NewResourcePoolSetDefaultEvent(
		ctx,
		resourcePool,
		cloudRegion.GetCloudProviderId().String(),
		cloudRegion.GetLogicalName(),
	)
	if evErr != nil {
		tilog.Warn(ctx, "failed to build set default resource pool event", zap.Error(evErr))
	} else {
		if writeErr := s.eventCommitter.Write(ctx, clusterevent.TopicClusterEvent, ev); writeErr != nil {
			tilog.Warn(ctx, "failed to write set default resource pool event", zap.Error(writeErr))
		}
	}

	return strategy, nil
}
