package region

import (
	"context"

	"github.com/samber/lo"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globalserverlessv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/serverless/v1"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func (s *regionServiceImpl) RegisterCloudProvider(
	ctx context.Context,
	req *globalserverlessv1.CloudProviderServiceRegisterRequest,
) (*globalcommonv1.CloudProvider, error) {
	ctx, span := tracer.Start(ctx, "RegisterCloudProvider")
	defer span.End()

	// check if cloud provider exists
	_, err := s.providerRepo.LoadByName(ctx, req.GetCloudProvider().Id)
	if err == nil {
		return nil, bizerr.New(bizerr.ErrCodeParams, "cloud provider already exists")
	}

	cloudProvider, err := s.providerRepo.Save(ctx, req.GetCloudProvider())
	if err != nil {
		return nil, bizerr.New(bizerr.ErrCodeUnknown, "save cloud provider failed: %w", err)
	}

	return cloudProvider, nil
}

func (s *regionServiceImpl) ListCloudProviders(
	ctx context.Context,
	req *globalserverlessv1.CloudProviderServiceListRequest,
) (*globalserverlessv1.CloudProviderServiceListResponse, error) {
	ctx, span := tracer.Start(ctx, "ListCloudProviders")
	defer span.End()

	cloudProviders, err := s.providerRepo.LoadAll(ctx)
	if err != nil {
		return nil, bizerr.New(bizerr.ErrCodeUnknown, "load cloud providers failed: %w", err)
	}

	if req.GetOrganizationId() == 0 &&
		req.GetCloudProviderId() == globalcommonv1.CloudProvider_NAME_UNSPECIFIED &&
		req.GetServicePlan() == globalcommonv1.ServicePlan_SERVICE_PLAN_UNSPECIFIED {
		return &globalserverlessv1.CloudProviderServiceListResponse{
			Total:          uint32(len(cloudProviders)),
			CloudProviders: cloudProviders,
		}, nil
	}

	cloudProvidersResp := make([]*globalcommonv1.CloudProvider, 0)
	for _, cloudProvider := range cloudProviders {
		// filter by cloud provider id
		if req.GetCloudProviderId() != globalcommonv1.CloudProvider_NAME_UNSPECIFIED &&
			req.GetCloudProviderId() != cloudProvider.Id {
			continue
		}
		var regions []*globalcommonv1.Region
		for _, region := range cloudProvider.Regions {
			// filter by service plan
			if req.GetServicePlan() != globalcommonv1.ServicePlan_SERVICE_PLAN_UNSPECIFIED &&
				req.GetServicePlan() != region.GetServicePlan() {
				continue
			}
			// filter by org with private region
			if !region.GetIsPublic() &&
				!lo.ContainsBy(
					region.GetOpenedTenantIds(),
					func(i uint64) bool { return i == req.GetOrganizationId() },
				) {
				continue
			}
			regions = append(regions, region)
		}

		if len(regions) == 0 {
			continue
		}
		cloudProvider.Regions = regions
		cloudProvidersResp = append(cloudProvidersResp, cloudProvider)
	}

	return &globalserverlessv1.CloudProviderServiceListResponse{
		Total:          uint32(len(cloudProvidersResp)),
		CloudProviders: cloudProvidersResp,
	}, nil
}
