package v1beta

import (
	"fmt"
	"strconv"

	"github.com/gin-gonic/gin"
	openapilegacy "github.com/tidbcloud/idl/pbgen/proto/openapi/cm"

	bffclusterv1beta1 "github.com/tidbcloud/tidb-management-service/api/spec/bff/cluster_management/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/internal/auth"
	"github.com/tidbcloud/tidb-management-service/tempo-wrapper/pkg/grpc"
	mgmtgrpc "github.com/tidbcloud/tidb-management-service/tempo-wrapper/pkg/grpc/mgmt"
	openapigrpc "github.com/tidbcloud/tidb-management-service/tempo-wrapper/pkg/grpc/openapi"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
)

func GetCluster(ctx *gin.Context) {
	req := &openapilegacy.GetClusterReq{}

	orgId, err := auth.GetOrgIDByHeader(ctx)
	if err != nil {
		types.OpenAPIInvalidArgumentResp(ctx, err)
		return
	}

	projectId, err := strconv.ParseUint(ctx.Param("project_id"), 10, 64)
	if err != nil {
		types.OpenAPIInvalidArgumentResp(ctx, fmt.Errorf("invalid project id: %w", err))
		return
	}

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

	req.ProjectId = projectId
	req.ClusterId = clusterId

	allow, err := apiutils.IsDedicatedAllow(ctx, orgId, projectId)
	if err != nil {
		types.OpenAPIInternalErrorResp(ctx, err)
		return
	}

	if allow {
		cluster, err := mgmtgrpc.GetCluster(grpc.NewContext(ctx), &bffclusterv1beta1.GetClusterRequest{
			ClusterId: strconv.FormatUint(clusterId, 10),
		})
		if err != nil {
			types.OpenAPIErrorResp(ctx, err)
			return
		}

		var cls *openapilegacy.ClusterItem

		switch cluster.GetClusterType() {
		case bffclusterv1beta1.Cluster_SERVERLESS:
			cls, err = convertServerlessCluster(cluster.GetServerlessCluster())
		case bffclusterv1beta1.Cluster_DEDICATED:
			cls, err = convertDedicatedCluster(grpc.NewContext(ctx), cluster.GetDedicatedCluster())
		default:
			err = fmt.Errorf("unknown cluster type: %s", cluster.GetClusterType().String())
		}

		if err != nil {
			types.OpenAPIErrorResp(ctx, err)
			return
		}
		types.SuccessResp(ctx, cls)
		return
	}

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

		resp, err := convertServerlessCluster(serverlessCluser)
		if err != nil {
			types.OpenAPIInternalErrorResp(ctx, err)
			return
		}
		types.SuccessResp(ctx, resp)
		return
	}

	// OpenAPI
	resp, err := openapigrpc.GetCluster(grpc.NewContext(ctx), req)
	if err != nil {
		types.OpenAPIErrorResp(ctx, err)
		return
	}

	if resp.ClusterType == openapilegacy.ClusterType_DEVELOPER {
		if ok, err := apiutils.IsServerlessAllow(ctx, orgId); err != nil {
			types.OpenAPIInternalErrorResp(ctx, fmt.Errorf("check allow list failed: %w", err))
			return
		} else if ok {
			// allowlisted ones are not allowed to return to serverless clusters from core-svc
			// not found
			types.OpenAPIErrorResp(ctx, bizerr.New(bizerr.ErrCodeRecordNotFound, "cluster is not found,id=%d", clusterId))
			return
		}
	}

	types.SuccessResp(ctx, resp)
}
