package privateendpoint

import (
	"context"
	"fmt"
	"strconv"

	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	openapingv1beta2 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/nextgen/v1beta2"
	"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 (s *serverImpl) GetPrivateLinkService(
	ctx context.Context,
	req *openapingv1beta2.GetPrivateLinkServiceRequest,
) (*openapingv1beta2.PrivateLinkService, error) {
	ctx, span := tracer.Start(ctx, "GetPrivateLinkService")
	defer span.End()

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

	tidbId, err := strconv.ParseUint(req.GetTidbId(), 10, 64)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "failed to parse tidb ID")
	}

	cluster, err := s.nextgenCli.GetCluster(ctx, &globalngv1.GetClusterRequest{
		ClusterId: tidbId,
	})
	if err != nil {
		return nil, err
	}

	services, err := s.nextgenCli.ListPrivateLinkServices(ctx, &globalngv1.ListPrivateLinkServicesRequest{
		ClusterId: tidbId,
	})
	if err != nil {
		return nil, err
	}
	if len(services.GetPrivateLinkServices()) == 0 {
		return &openapingv1beta2.PrivateLinkService{}, nil
	}
	if len(services.GetPrivateLinkServices()) > 1 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "multiple private link services found")
	}

	return privateLinkServiceToOpenapi(services.GetPrivateLinkServices()[0], cluster)
}

func privateLinkServiceToOpenapi(
	service *globalngv1.PrivateLinkService,
	cluster *globalngv1.Cluster,
) (*openapingv1beta2.PrivateLinkService, bizerr.BizError) {
	_, regionId, cloudProvider, err := common.BuildOpenApiRegionName(
		cluster.GetCloudProviderId().String(),
		cluster.GetRegionId().String(),
	)
	if err != nil {
		return nil, bizerr.WrapErrorWithCode(err, bizerr.ErrCodeParams, "failed to build region ID")
	}

	return &openapingv1beta2.PrivateLinkService{
		Name:              fmt.Sprintf("tidbs/%d/privateLinkService", service.GetClusterId()),
		TidbId:            strconv.FormatUint(service.GetClusterId(), 10),
		RegionId:          regionId,
		RegionDisplayName: cluster.GetRegionDisplayName(),
		CloudProvider:     cloudProvider,
		ServiceName:       service.GetServiceName(),
		ServiceDnsName:    service.GetServiceDnsName(),
		AvailableZones:    service.GetAvailableZones(),
		ServicePort:       service.GetServicePort(),
		State:             privateLinkServiceStateToOpenapi(service.GetState()),
	}, nil
}

func privateLinkServiceStateToOpenapi(
	state globalngv1.PrivateLinkService_State,
) openapingv1beta2.PrivateLinkService_State {
	switch state {
	case globalngv1.PrivateLinkService_ACTIVE:
		return openapingv1beta2.PrivateLinkService_ACTIVE
	case globalngv1.PrivateLinkService_DELETING:
		return openapingv1beta2.PrivateLinkService_DELETING
	case globalngv1.PrivateLinkService_CREATING:
		return openapingv1beta2.PrivateLinkService_CREATING
	default:
		return openapingv1beta2.PrivateLinkService_STATE_UNSPECIFIED
	}
}
