package region

import (
	"context"
	"strconv"

	"github.com/samber/lo"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globaldedicatedv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/dedicated/v1"
	openapicommonv1beta1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/common/v1beta1"
	openapidedicatedv1beta1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/dedicated/v1beta1"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/pkg/apimiddleware/bizerror"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-service/pkg/common"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/grpc/metadata"
)

func (t serverImpl) ShowCloudProviders(
	ctx context.Context,
	req *openapidedicatedv1beta1.ShowCloudProvidersRequest,
) (*openapidedicatedv1beta1.ShowCloudProvidersResponse, error) {
	ctx, span := tracer.Start(ctx, "ShowCloudProviders")
	defer span.End()

	// Extract request meta.
	reqMeta, err := metadata.ExtractRequestMetaWithCheckPermission(ctx)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "failed to extract request metadata")
	}

	projectId := reqMeta.DefaultProjectID
	if req.GetProjectId() != "" {
		projectId, err = strconv.ParseUint(req.GetProjectId(), 10, 64)
		if err != nil {
			return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "invalid project id")
		}
	}

	cloudProviders, err := t.listProviders(ctx, reqMeta.OrgID, projectId)
	if err != nil {
		return nil, err
	}

	ps := make([]openapicommonv1beta1.Region_CloudProvider, 0)
	for _, p := range cloudProviders {
		provider := common.GlobalProviderToOpenApi(p.GetId())
		ps = append(ps, provider)
	}

	return &openapidedicatedv1beta1.ShowCloudProvidersResponse{CloudProviders: ps}, nil
}

func (t serverImpl) listProviders(
	ctx context.Context,
	orgId, projectId uint64,
) ([]*globalcommonv1.CloudProvider, error) {
	resp, err := t.dedicatedCli.ListCloudProviders(ctx, &globaldedicatedv1.ListCloudProvidersRequest{
		OrganizationId: orgId,
		ProjectId:      projectId,
	})
	if err != nil {
		return nil, bizerror.NewInternal(err, "failed to list cloud providers")
	}

	thirdProviders, err := t.accountCli.GetTenantThirdPartyAccountProviders(ctx, orgId)
	if err != nil {
		return nil, bizerr.WrapGrpcError(err, "failed to get third party account providers")
	}

	ps := make([]*globalcommonv1.CloudProvider, 0)
	for _, p := range resp.GetCloudProviders() {
		provider := common.GlobalProviderToOpenApi(p.GetId())
		// if third party account providers exist
		if len(thirdProviders) > 0 && !lo.Contains(thirdProviders, provider) {
			continue
		}
		ps = append(ps, p)
	}

	return ps, nil
}
