package server

import (
	"context"
	"strings"

	apiv1 "github.com/tidbcloud/cluster-service-ng/api/cluster-service-ng/v1beta"
	dplanemgrv1 "github.com/tidbcloud/cluster-service-ng/api/dataplane-manager/v1"
	"github.com/tidbcloud/cluster-service-ng/domain/entity"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

func (s *serverImpl) EvaluateSharedPoolNetworkCapacity(
	ctx context.Context,
	req *entity.EvaluateSharedPoolNetworkCapacityRequest,
) (*entity.EvaluateSharedPoolNetworkCapacityResponse, error) {
	if req == nil || req.CidrPrefixLength == nil {
		return nil, status.Error(codes.InvalidArgument, "cidr_prefix_length is required")
	}
	if req.GetCidrPrefixLength() < 0 || req.GetCidrPrefixLength() > 32 {
		return nil, status.Error(codes.InvalidArgument, "cidr_prefix_length must be between 0 and 32")
	}

	var highAvailability dplanemgrv1.DataPlane_HighAvailabilityType
	switch req.GetHighAvailabilityType() {
	case apiv1.CreateSharedPoolRequest_InitSharedPoolConfig_REGIONAL:
		highAvailability = dplanemgrv1.DataPlane_REGIONAL
	case apiv1.CreateSharedPoolRequest_InitSharedPoolConfig_ZONAL:
		highAvailability = dplanemgrv1.DataPlane_ZONAL
	case apiv1.CreateSharedPoolRequest_InitSharedPoolConfig_HIGH_AVAILABILITY_TYPE_UNSPECIFIED:
		return nil, status.Error(codes.InvalidArgument, "high_availability_type is required")
	default:
		return nil, status.Errorf(codes.InvalidArgument, "unknown high_availability_type %d", req.GetHighAvailabilityType())
	}
	switch highAvailability {
	case dplanemgrv1.DataPlane_REGIONAL:
		if len(req.GetNodeZones()) == 1 {
			return nil, status.Error(codes.InvalidArgument, "node_zones with 1 zone means a zonal evaluation; use high_availability_type=ZONAL or pass 2+ zones for REGIONAL")
		}
	case dplanemgrv1.DataPlane_ZONAL:
		if len(req.GetNodeZones()) > 1 {
			return nil, status.Error(codes.InvalidArgument, "node_zones must contain at most 1 zone for zonal evaluation")
		}
		if len(req.GetNodeZones()) == 1 && strings.TrimSpace(req.GetNodeZones()[0]) == "" {
			return nil, status.Error(codes.InvalidArgument, "node_zones must not contain an empty zone")
		}
	}

	accountID := ""
	if s.bizCfg != nil {
		accountID = strings.TrimSpace(s.bizCfg.DefaultDataplaneAccount)
	}
	result, err := s.dataplaneClient.EvaluateDataPlaneNetworkCapacity(ctx, &dplanemgrv1.EvaluateDataPlaneNetworkCapacityRequest{
		CidrPrefixLength:     req.CidrPrefixLength,
		HighAvailabilityType: highAvailability,
		AccountId:            accountID,
		NodeZones:            req.GetNodeZones(),
	})
	if err != nil {
		return nil, err
	}
	if result == nil {
		return nil, status.Error(codes.Internal, "dataplane manager returned an empty network capacity response")
	}
	if result.GetSupported() && result.GetSupportedNodeCount() <= 0 {
		return nil, status.Error(codes.Internal, "dataplane manager returned supported with a nonpositive node count")
	}
	if !result.GetSupported() && result.GetSupportedNodeCount() != 0 {
		return nil, status.Error(codes.Internal, "dataplane manager returned unsupported with a nonzero node count")
	}
	return &entity.EvaluateSharedPoolNetworkCapacityResponse{
		Supported:          result.GetSupported(),
		SupportedNodeCount: result.GetSupportedNodeCount(),
	}, nil
}
