package bff

import (
	"context"
	"fmt"
	"time"

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

	bffclusterv1beta2 "github.com/tidbcloud/tidb-management-service/api/spec/bff/cluster_management/v1beta2"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-portal/app/common"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-portal/domain/service/auth"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-portal/domain/service/rbac"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-portal/infra/accountimpl"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-portal/pkg/apimiddleware/reqmodifier"
	"github.com/tidbcloud/tidb-management-service/tidb-mgmt-portal/pkg/config"
)

func SetupOneConsoleApiHandler(eng *gin.Engine, timeout time.Duration) error {
	address := config.Global().TiDBMgmtServiceConfig.Address

	conn, err := common.CreateGrpcConn(address, timeout)
	if err != nil {
		return errtrace.Wrap(fmt.Errorf("failed to dial server: %w", err))
	}

	err = registerOneConsoleHandlers(eng, conn)
	if err != nil {
		return errtrace.Wrap(fmt.Errorf("failed to register gateway: %w", err))
	}
	return nil
}

func registerOneConsoleHandlers(eng *gin.Engine, conn *grpc.ClientConn) error {
	gwmux := common.MakeGatewayMux()

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

	err = bffclusterv1beta2.RegisterTiDBServiceHandler(context.Background(), gwmux, conn)
	if err != nil {
		return errtrace.Wrap(err)
	}

	// init common middlewares
	accountClient := accountimpl.NewAccount()

	var authNService = auth.NewTiDBXAuthNService(accountClient)
	var authZService = rbac.NewTiDBXAuthZService(accountClient)

	apiGroup := eng.Group("/api/v2023/clusterManagement/v1beta2")
	apiGroup.Use(
		authNService.RemoveApiKeyHeader,
		authNService.GetIdentityInfo(),
		authNService.TransTokenUser,
		authZService.CheckUriRbac,
		authZService.SetGrpcGatewayMetaData,
	)
	apiGroup.Use(reqmodifier.ServePathStartFromAny)
	apiGroup.Use(reqmodifier.RewriteBracketParams())
	apiGroup.Any("/*any", gin.WrapF(gwmux.ServeHTTP))

	return nil
}
