package privatelink

import (
	"context"
	"strconv"

	clusterngv1beta "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"

	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/privatelink"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func (s *service) ListPrivateLinkServices(
	ctx context.Context,
	req *globalngv1.ListPrivateLinkServicesRequest,
) ([]*entity.PrivateLinkService, bizerr.BizError) {
	ctx, span := tracer.Start(ctx, "privatelinkservice.ListPrivateLinkServices")
	defer span.End()

	if req.ClusterId == 0 {
		return nil, bizerr.New(bizerr.ErrCodeParams, "cluster_id is required")
	}
	cluster, err := s.clusterRepo.Get(ctx, req.ClusterId, false)
	if err != nil {
		return nil, err
	}
	if cluster == nil {
		return nil, bizerr.New(bizerr.ErrCodeParams, "cluster not found")
	}

	if req.TidbGroupId != 0 {
		tidbGroup, err := s.tidbGroupRepo.Load(ctx, req.ClusterId, req.TidbGroupId)
		if err != nil {
			return nil, err
		}
		if tidbGroup == nil {
			return nil, bizerr.New(bizerr.ErrCodeParams, "tidb_group not found")
		}
	}

	services, err := s.privatelinkRepo.ListPrivateLinkServices(ctx, &privatelink.Filter{
		ClusterID:   req.ClusterId,
		TidbGroupID: req.TidbGroupId,
	})
	if err != nil {
		return nil, err
	}

	if len(services) == 0 {
		return []*entity.PrivateLinkService{}, nil
	}

	region, err := s.regionRepo.Get(ctx, cluster.RegionId)
	if err != nil {
		return nil, err
	}

	outputs := make([]*entity.PrivateLinkService, 0, len(services))
	for _, service := range services {
		regionalService, err := s.regionalCli.GetPrivateLinkService(
			ctx,
			region,
			&clusterngv1beta.GetPrivateLinkServiceRequest{
				ClusterId:            strconv.FormatUint(cluster.ClusterId, 10),
				TidbGroupId:          strconv.FormatUint(service.TidbGroupId, 10),
				PrivateLinkServiceId: strconv.FormatUint(service.PrivateLinkServiceID, 10),
			},
		)
		if err != nil {
			return nil, err
		}
		service.State = coverToGlobalPrivateLinkServiceState(regionalService.Status)

		switch {
		case regionalService.GetAws() != nil:
			service.ServiceName = regionalService.GetAws().GetServiceName()
			service.AvailableZones = regionalService.GetAws().GetAzIds()
		case regionalService.GetAzure() != nil:
			service.ServiceName = regionalService.GetAzure().GetServiceResourceId()
		case regionalService.GetGcp() != nil:
			service.ServiceName = regionalService.GetGcp().GetServiceAttachment()
		case regionalService.GetAliCloud() != nil:
			service.ServiceName = regionalService.GetAliCloud().GetServiceName()
			service.AvailableZones = regionalService.GetAliCloud().GetAzIds()
		default:
			return nil, bizerr.New(bizerr.ErrCodeParams, "unknown cloud provider for private link service")
		}
		service.ServiceDnsName = regionalService.GetServiceDnsName()
		outputs = append(outputs, service)
	}

	return outputs, nil
}

func coverToGlobalPrivateLinkServiceState(
	state clusterngv1beta.PrivateLinkService_Status,
) globalngv1.PrivateLinkService_State {
	switch state {
	case clusterngv1beta.PrivateLinkService_ACTIVE:
		return globalngv1.PrivateLinkService_ACTIVE
	case clusterngv1beta.PrivateLinkService_CREATING:
		return globalngv1.PrivateLinkService_CREATING
	case clusterngv1beta.PrivateLinkService_DELETING:
		return globalngv1.PrivateLinkService_DELETING
	default:
		return globalngv1.PrivateLinkService_STATE_UNSPECIFIED
	}
}
