package central

import (
	"fmt"
	"strconv"

	"github.com/gin-gonic/gin"
	centralapi "github.com/tidbcloud/core-svc/idl/pbgen/proto/central"
	"google.golang.org/protobuf/types/known/emptypb"

	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"
	coregrpc "github.com/tidbcloud/tidb-management-service/tempo-wrapper/pkg/grpc/core_portal"
	mgmtgrpc "github.com/tidbcloud/tidb-management-service/tempo-wrapper/pkg/grpc/mgmt"
)

func CreatePrivateEndpoint(ctx *gin.Context) {
	req := &centralapi.ClusterIdReq{}
	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.BadRequestResp(ctx, fmt.Errorf("invalid org id: %w", err))
		return
	}
	projectId, err := strconv.ParseUint(ctx.Param("project_id"), 10, 64)
	if err != nil {
		types.BadRequestResp(ctx, fmt.Errorf("invalid project id: %w", err))
		return
	}

	clusterId, err := strconv.ParseUint(ctx.Param("cluster_id"), 10, 64)
	if err != nil {
		types.BadRequestResp(ctx, fmt.Errorf("invalid cluster id: %w", err))
		return
	}

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

	if ok, err := apiutils.IsNewServerlessCluster(ctx, clusterId, projectId, orgId); err != nil {
		types.InternalErrorResp(ctx, fmt.Errorf("check cluster failed: %w", err))
		return
	} else if ok {
		types.SuccessResp(ctx, &emptypb.Empty{})
		return
	}

	// TDDO: use new open api
	// if ok, err := apiutils.IsNewDedicatedCluster(ctx, clusterId, projectId, orgId); err != nil {
	// 	types.InternalErrorResp(ctx, fmt.Errorf("check cluster failed: %w", err))
	// 	return
	// } else if ok {
	// 	types.SuccessResp(ctx, &emptypb.Empty{})
	// 	return
	// }

	// core-portal will split traffic to dedicated global
	// https://github.com/tidbcloud/core-svc/pull/1316
	resp, err := coregrpc.CreatePrivateEndpoint(grpc.NewContext(ctx), req)
	if err != nil {
		types.GrpcErrorResp(ctx, err)
		return
	}
	types.SuccessResp(ctx, resp)
}

func GetPrivateEndpoint(ctx *gin.Context) {
	req := &centralapi.ClusterIdReq{}
	// check org/project id
	orgId, err := strconv.ParseUint(ctx.Param("org_id"), 10, 64)
	if err != nil {
		types.BadRequestResp(ctx, fmt.Errorf("invalid org id: %w", err))
		return
	}
	projectId, err := strconv.ParseUint(ctx.Param("project_id"), 10, 64)
	if err != nil {
		types.BadRequestResp(ctx, fmt.Errorf("invalid project id: %w", err))
		return
	}

	clusterId, err := strconv.ParseUint(ctx.Param("cluster_id"), 10, 64)
	if err != nil {
		types.BadRequestResp(ctx, fmt.Errorf("invalid cluster id: %w", err))
		return
	}

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

	if ok, err := apiutils.IsNewServerlessCluster(ctx, clusterId, projectId, orgId); err != nil {
		types.InternalErrorResp(ctx, fmt.Errorf("check cluster failed: %w", err))
		return
	} else if ok {
		cluster, err := mgmtgrpc.GetServerlessCluster(grpc.NewContext(ctx), &openapiserverlessv1beta1.GetClusterRequest{
			ClusterId: strconv.FormatUint(clusterId, 10),
			View:      openapiserverlessv1beta1.ClusterView_BASIC,
		})
		if err != nil {
			types.GrpcErrorResp(ctx, err)
			return
		}
		types.SuccessResp(ctx, convertPrivateEndpoint(cluster))
		return
	}

	// TDDO: use new open api
	// if ok, err := apiutils.IsNewDedicatedCluster(ctx, clusterId, projectId, orgId); err != nil {
	// 	types.InternalErrorResp(ctx, fmt.Errorf("check cluster failed: %w", err))
	// 	return
	// } else if ok {
	// 	types.SuccessResp(ctx, &emptypb.Empty{})
	// 	return
	// }

	// core-portal will split traffic to dedicated global
	// https://github.com/tidbcloud/core-svc/pull/1316
	resp, err := coregrpc.GetPrivateEndpoint(grpc.NewContext(ctx), req)
	if err != nil {
		types.GrpcErrorResp(ctx, err)
		return
	}
	types.SuccessResp(ctx, resp)
}

func convertPrivateEndpoint(c *openapiserverlessv1beta1.Cluster) *centralapi.GetPrivateEndpointResp {
	if c.Endpoints == nil || c.Endpoints.Private == nil || c.Endpoints.Private.Host == "" {
		return &centralapi.GetPrivateEndpointResp{
			Status: centralapi.PrivateEndpointStatus_NO_VPC_PEERING,
		}
	}

	resp := &centralapi.GetPrivateEndpointResp{
		Status: centralapi.PrivateEndpointStatus_NORMAL,
		Port:   uint64(c.Endpoints.Private.Port),
		Domain: c.Endpoints.Private.Host,
	}

	// switch provider := c.Endpoints.PrivateEndpoint.Provider.(type) {
	// case *openapiserverlessv1beta1.Cluster_Endpoints_Private_Aws:
	// 	resp.Domain = provider.Aws.ServiceName
	// case *openapiserverlessv1beta1.Cluster_Endpoints_Private_Gcp:
	// 	resp.Domain = provider.Gcp.ServiceAttachmentName
	// }

	return resp
}
