package openapi

import (
	"context"

	"braces.dev/errtrace"
	"github.com/gin-gonic/gin"
	"google.golang.org/grpc"

	openapifsv1beta2 "github.com/tidbcloud/tidb-management-service/api/spec/tidb_cloud_open_api/fs/v1beta2"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-portal/app/common"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-portal/pkg/apimiddleware/reqmodifier"
)

// OpenAPI and WebUI API are served by the same handler, but have different base paths.
//
// Original request host and base path from outside:
// - OpenAPI: https://fs.tidbapi.com/v1beta2
// - WebUI API: https://us-west-2.prod.aws.tidbcloud.com/api/v2025/fs/v1beta2
//
// After Kong pre-processing:
// - OpenAPI: http://tidb-mgmt-portal-svc/fs/v1beta2
// - WebUI API: http://tidb-mgmt-portal-svc/api/v2025/fs/v1beta2
//
// gRPC-Gateway serves handlers without base path.
//
// Thus, we strip the base paths of the Kong pre-processed requests, to use the same gRPC handler to serve both OpenAPI and WebUI API.
func registerFsV1beta2Handlers(
	eng *gin.Engine,
	conn *grpc.ClientConn,
	openApiMiddlewares, uiApiMiddlewares []gin.HandlerFunc,
) error {
	gwmux := common.MakeGatewayMux()

	if err := openapifsv1beta2.RegisterRegionServiceHandler(context.Background(), gwmux, conn); err != nil {
		return errtrace.Wrap(err)
	}

	openapi := eng.Group("/fs/v1beta2")
	uiapi := eng.Group("/api/v2025/fs/v1beta2")

	for _, apiGroup := range []*gin.RouterGroup{openapi} {
		apiGroup.Use(openApiMiddlewares...)
		// strip the base paths of the Kong pre-processed requests, to use the same gRPC handler to serve both OpenAPI and WebUI API.
		apiGroup.Use(reqmodifier.ServePathStartFromAny)
		apiGroup.Any("/*any", gin.WrapF(gwmux.ServeHTTP))
	}

	for _, apiGroup := range []*gin.RouterGroup{uiapi} {
		apiGroup.Use(uiApiMiddlewares...)
		// strip the base paths of the Kong pre-processed requests, to use the same gRPC handler to serve both OpenAPI and WebUI API.
		apiGroup.Use(reqmodifier.ServePathStartFromAny)
		apiGroup.Any("/*any", gin.WrapF(gwmux.ServeHTTP))
	}

	return nil
}
