package auth

import (
	"net/http"
	"sync"

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
)

var (
	onceGinChecker        PermissionChecker
	onceGinCheckerInit    sync.Once
	onceGinCheckerInitErr error
)

func GinPermissionCheckInterceptor(commonParam *PermissionCheckerCommonParam) func(ctx *gin.Context) {
	return func(c *gin.Context) {
		ctx := c.Request.Context()
		checker, err := GetGinPermissionChecker(commonParam)
		if err != nil {
			tilog.Warn(ctx, "GetGinPermissionChecker error", zap.Any("err", err))
			c.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
			c.Abort()
			return
		}
		var accessParam *AccessParam
		if commonParam.GenAccessParam4GinF != nil {
			accessParam, err = commonParam.GenAccessParam4GinF(c)
			if err != nil {
				tilog.Warn(ctx, "custom GenAccessParam4GinF exec error", zap.Any("err", err))
				c.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
				c.Abort()
				return
			}
		} else {
			accessParam = GenAccessParam4GinByDefault(c)
		}
		accessParam.Metadata[AccessMetadataResourceMapKey] = commonParam.PathPattern2ResourceMap
		accessParam.Metadata[AccessMetadataRequestWhitelistKey] = commonParam.PathWhitelist

		result, err := checker.Handle(ctx, accessParam)
		// if biz need to change the logic, biz can rewrite PermissionCheckResultHandleFunc and set to HttpReqCheckRetHandleF
		checkRetHandleF := defaultPermissionCheckResultHandleFunc
		if commonParam.HttpReqCheckRetHandleF != nil {
			checkRetHandleF = commonParam.HttpReqCheckRetHandleF
		}
		if !checkRetHandleF(c.Writer, c.Request, result, err) {
			c.Abort()
			return
		}
		c.Next()
	}
}

func GetGinPermissionChecker(commonParam *PermissionCheckerCommonParam) (PermissionChecker, error) {
	onceGinCheckerInit.Do(func() {
		onceGinChecker, onceGinCheckerInitErr = NewPermissionCheckerWithCommonParam(commonParam)
	})
	return onceGinChecker, onceGinCheckerInitErr
}
