package central

import (
	"fmt"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
	centralapi "github.com/tidbcloud/core-svc/idl/pbgen/proto/central"

	openapidedicatedv1beta1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/dedicated/v1beta1"
	openapiserverlessv1beta1 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/serverless/v1beta1"
	"github.com/tidbcloud/tidb-management-service/tempo-wrapper/internal/api/types"
	apiutils "github.com/tidbcloud/tidb-management-service/tempo-wrapper/internal/api/utils"
	"github.com/tidbcloud/tidb-management-service/tempo-wrapper/pkg/grpc"
	mgmtgrpc "github.com/tidbcloud/tidb-management-service/tempo-wrapper/pkg/grpc/mgmt"
)

func ListRegions(ctx *gin.Context) {
	req := &centralapi.ListCloudProvidersReq{}
	err := types.ShouldBindJSON(ctx, req)
	if err != nil {
		types.BadRequestResp(ctx, fmt.Errorf("bind request body failed: %w", err))
		return
	}

	// check org/project id
	orgId, err := strconv.ParseUint(ctx.Param("org_id"), 10, 64)
	if err != nil {
		types.UnauthorizedResp(ctx, err)
		return
	}
	projectId, err := strconv.ParseUint(ctx.Param("project_id"), 10, 64)
	if err != nil {
		types.UnauthorizedResp(ctx, err)
		return
	}

	// set org and project id
	req.OrgId = orgId
	req.ProjectId = projectId

	// serverless
	if req.IsDevTier {
		allow, err := apiutils.IsServerlessAllow(ctx, orgId)
		if err != nil {
			types.InternalErrorResp(ctx, err)
			return
		}
		if allow {
			resp, err := mgmtgrpc.ListServerlessRegions(grpc.NewContext(ctx))
			if err != nil {
				types.GrpcErrorResp(ctx, err)
				return
			}
			types.SuccessResp(ctx, convertServerlessRegionResp(resp))
			return
		}
	}

	resp, err := mgmtgrpc.ListDedicatedRegions(
		grpc.NewContext(ctx),
		&openapidedicatedv1beta1.ListRegionsRequest{ProjectId: ctx.Param("project_id")},
	)
	if err != nil {
		types.GrpcErrorResp(ctx, err)
		return
	}
	types.SuccessResp(ctx, convertDedicatedRegionResp(resp))
}

func convertServerlessRegionResp(r *openapiserverlessv1beta1.ListRegionsResponse) *centralapi.CloudProviders {
	resp := &centralapi.CloudProviders{
		BaseResp: &centralapi.BaseResp{
			ErrCode: 0,
		},
	}

	// provider
	providerRegion := make(map[string][]*centralapi.Region)
	for _, region := range r.Regions {
		providerRegion[strings.ToLower(region.CloudProvider.String())] = append(
			providerRegion[strings.ToLower(region.CloudProvider.String())],
			&centralapi.Region{
				Name:        apiutils.ConvertRegionName(region.Name),
				DisplayName: region.DisplayName,
			},
		)
	}

	for provider, regions := range providerRegion {
		resp.CloudProviders = append(resp.CloudProviders, &centralapi.CloudProvider{
			Name:    provider,
			Regions: regions,
		})
	}

	return resp
}

func convertDedicatedRegionResp(r *openapidedicatedv1beta1.ListRegionsResponse) *centralapi.CloudProviders {
	resp := &centralapi.CloudProviders{
		BaseResp: &centralapi.BaseResp{
			ErrCode: 0,
		},
	}

	providerRegion := make(map[string][]*centralapi.Region)

	for _, region := range r.Regions {
		ps := region.CloudProvider.String()
		providerRegion[ps] = append(providerRegion[ps], &centralapi.Region{
			Name:        apiutils.ConvertRegionName(region.Name),
			DisplayName: region.DisplayName,
		})
	}

	for provider, regions := range providerRegion {
		resp.CloudProviders = append(resp.CloudProviders, &centralapi.CloudProvider{
			Name:    provider,
			Regions: regions,
		})
	}

	return resp
}
