package middleware

import (
	"context"
	"kra/internal/biz/system"

	"kra/internal/conf"
	"kra/internal/service"

	"github.com/gin-gonic/gin"
)

type accessController interface {
	Authorize(context.Context, uint, string, string) (bool, error)
	ContextWithDataScope(context.Context, uint, uint) (context.Context, error)
}

func AccessControl(runtime *conf.Runtime, access accessController) gin.HandlerFunc {
	return func(c *gin.Context) {
		claims := Claims(c)
		if claims == nil {
			NoAuth(c, "未登录或非法访问")
			return
		}
		if access == nil {
			Write(c, CodeError, gin.H{}, "权限服务不可用")
			c.Abort()
			return
		}
		path := c.Request.URL.Path
		policyPath := path
		if config := runtime.Admin(); config != nil {
			policyPath = service.NormalizeRoutePath(policyPath, config.RouterPrefix)
		}
		allowed, err := access.Authorize(c.Request.Context(), claims.AuthorityID, policyPath, c.Request.Method)
		if err != nil || !allowed {
			Write(c, CodeError, gin.H{}, "权限不足")
			c.Abort()
			return
		}
		requestContext, err := access.ContextWithDataScope(c.Request.Context(), claims.AuthorityID, claims.ID)
		if err != nil {
			Write(c, CodeError, gin.H{}, "数据权限解析失败")
			c.Abort()
			return
		}
		if scope, ok := system.DataScopeFromContext(requestContext); ok {
			requestID, _ := c.Get("request_id")
			scope.RequestID, _ = requestID.(string)
			scope.Method, scope.Path = c.Request.Method, path
			requestContext = system.NewDataScopeContext(requestContext, scope)
		}
		requestContext = system.NewActorContext(requestContext, system.Actor{UserID: claims.ID, AuthorityID: claims.AuthorityID})
		c.Request = c.Request.WithContext(requestContext)
		c.Next()
	}
}
