package useadapter

import (
	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/account/idl/pbgen/proto/account"
	"github.com/tidbcloud/tiinf/sdk/rbac"
	"github.com/tidbcloud/tiinf/sdk/rbac/common"
	"google.golang.org/protobuf/encoding/protojson"
)

// -------- for gin interceptor -----------------------
// gin extract userid need set userid to gin.Context.Keys

func GinPermissionCheckInterceptorWithCommonParam(commonParam *rbac.PermissionCheckerCommonParam) func(ctx *gin.Context) {
	return func(c *gin.Context) {
		checker := rbac.GetPermissionCheckerWithCommonParam(commonParam)
		result, err := checker.Handle(c.Request.Context(), GenAccessParam4Gin(c))
		if !DefaultAccessDecideCompleteExecFunc(c.Writer, c.Request, result, err) {
			c.Abort()
			return
		}
		c.Next()
	}
}

// Deprecated
func GinPermissionCheckInterceptor(
	identityF common.GetIdentityFunc,
	resourceMap map[string]string,
	pathWhitelist ...string) func(ctx *gin.Context) {
	return func(c *gin.Context) {
		checker := rbac.GetPermissionCheckerWithDefaultHelper(identityF, resourceMap, pathWhitelist...)
		result, err := checker.Handle(c.Request.Context(), GenAccessParam4Gin(c))
		if !DefaultAccessDecideCompleteExecFunc(c.Writer, c.Request, result, err) {
			c.Abort()
			return
		}
		c.Next()
	}
}

// Deprecated
func GinPermissionCheckInterceptorWithAccountClient(
	accountClient *account.AccountAPIServiceClient,
	identityF common.GetIdentityFunc,
	resourceMap map[string]string,
	pathWhitelist ...string) func(ctx *gin.Context) {
	return func(c *gin.Context) {
		checker := rbac.GetPermissionCheckerWithAccountClient(*accountClient, identityF, resourceMap, pathWhitelist...)
		result, err := checker.Handle(c.Request.Context(), GenAccessParam4Gin(c))
		if !DefaultAccessDecideCompleteExecFunc(c.Writer, c.Request, result, err) {
			c.Abort()
			return
		}
		c.Next()
	}
}

func GenAccessParam4Gin(c *gin.Context) *common.AccessParam {
	param := common.AccessParam{
		Metadata: map[string]interface{}{
			common.METADATA_PATH:   c.Request.URL.Path,
			common.METADATA_METHOD: c.Request.Method,
		},
		Req: c,
	}
	return &param
}

// marshalOptions is a configurable JSON format marshaller.
var marshalOptions = protojson.MarshalOptions{
	UseProtoNames:   true,
	EmitUnpopulated: true,
}
