package middleware

import (
	"net/http"

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

// contextKey 上下文键常量
const (
	ContextKeyRoleCodes       = "role_codes"
	ContextKeyPermissionCodes = "permission_codes"
)

// RequirePermission 要求用户拥有指定权限之一（OR 逻辑）
// 适用于需要单个或多选权限校验的路由
func RequirePermission(codes ...string) gin.HandlerFunc {
	return func(c *gin.Context) {
		if !hasAnyPermission(c, codes) {
			c.JSON(http.StatusForbidden, gin.H{
				"code":    403,
				"message": "权限不足",
			})
			c.Abort()
			return
		}
		c.Next()
	}
}

// RequireAllPermissions 要求用户拥有所有指定权限（AND 逻辑）
func RequireAllPermissions(codes ...string) gin.HandlerFunc {
	return func(c *gin.Context) {
		if !hasAllPermissions(c, codes) {
			c.JSON(http.StatusForbidden, gin.H{
				"code":    403,
				"message": "权限不足，需要所有指定权限",
			})
			c.Abort()
			return
		}
		c.Next()
	}
}

// RequireRole 要求用户拥有指定角色之一（OR 逻辑）
func RequireRole(codes ...string) gin.HandlerFunc {
	return func(c *gin.Context) {
		if !hasAnyRole(c, codes) {
			c.JSON(http.StatusForbidden, gin.H{
				"code":    403,
				"message": "权限不足，角色受限",
			})
			c.Abort()
			return
		}
		c.Next()
	}
}

// RequireAnyPermission RequirePermission 的别名，语义更清晰
func RequireAnyPermission(codes ...string) gin.HandlerFunc {
	return RequirePermission(codes...)
}

// AdminOnly 仅限 admin 角色
func AdminOnly() gin.HandlerFunc {
	return RequireRole("admin")
}

// GetRoleCodes 从 Context 获取当前用户角色代码列表
func GetRoleCodes(c *gin.Context) []string {
	val, exists := c.Get(ContextKeyRoleCodes)
	if !exists {
		return nil
	}
	if codes, ok := val.([]string); ok {
		return codes
	}
	return nil
}

// GetPermissionCodes 从 Context 获取当前用户权限代码列表
func GetPermissionCodes(c *gin.Context) []string {
	val, exists := c.Get(ContextKeyPermissionCodes)
	if !exists {
		return nil
	}
	if codes, ok := val.([]string); ok {
		return codes
	}
	return nil
}

// IsAdmin 判断当前用户是否为 admin
func IsAdmin(c *gin.Context) bool {
	return hasAnyRole(c, []string{"admin"})
}

// hasAnyPermission 判断用户是否拥有任意一个权限
func hasAnyPermission(c *gin.Context, codes []string) bool {
	// admin 角色拥有所有权限
	if IsAdmin(c) {
		return true
	}
	permCodes := GetPermissionCodes(c)
	if len(permCodes) == 0 {
		return false
	}
	permSet := toSet(permCodes)
	for _, code := range codes {
		if _, ok := permSet[code]; ok {
			return true
		}
	}
	return false
}

// hasAllPermissions 判断用户是否拥有所有权限
func hasAllPermissions(c *gin.Context, codes []string) bool {
	if IsAdmin(c) {
		return true
	}
	permCodes := GetPermissionCodes(c)
	permSet := toSet(permCodes)
	for _, code := range codes {
		if _, ok := permSet[code]; !ok {
			return false
		}
	}
	return true
}

// hasAnyRole 判断用户是否拥有任意一个角色
func hasAnyRole(c *gin.Context, codes []string) bool {
	roleCodes := GetRoleCodes(c)
	if len(roleCodes) == 0 {
		return false
	}
	roleSet := toSet(roleCodes)
	for _, code := range codes {
		if _, ok := roleSet[code]; ok {
			return true
		}
	}
	return false
}

// toSet 将字符串切片转换为 map 集合
func toSet(items []string) map[string]struct{} {
	s := make(map[string]struct{}, len(items))
	for _, item := range items {
		s[item] = struct{}{}
	}
	return s
}
