package handlers

import (
	"context"
	"net/http"
	"time"

	"go.mongodb.org/mongo-driver/v2/bson"
	"go.mongodb.org/mongo-driver/v2/mongo"

	"yh_web/server/config"
	"yh_web/server/models"

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

// roleIDFromContext 从 context 安全取 role_id（JWT 等可能解码为 float64）
func roleIDFromContext(c *gin.Context) (int, bool) {
	roleIDVal, ok := c.Get("role_id")
	if !ok {
		return 0, false
	}
	switch v := roleIDVal.(type) {
	case int:
		return v, true
	case float64:
		return int(v), true
	default:
		return 0, false
	}
}

// getPermissionsByRoleID 从 role_permissions 读取某角色的权限；9527 默认拥有全部
func getPermissionsByRoleID(ctx context.Context, roleID int) []string {
	if roleID == models.RoleIDSuperAdmin {
		return allPermissionKeys()
	}
	coll := config.GetDB(config.DBName).Collection("role_permissions")
	var doc models.RolePermissionsDoc
	err := coll.FindOne(ctx, bson.M{"role_id": roleID}).Decode(&doc)
	if err != nil {
		if err == mongo.ErrNoDocuments {
			return nil
		}
		return nil
	}
	return doc.Permissions
}

func allPermissionKeys() []string {
	keys := make([]string, 0, len(models.AllPermissions))
	for _, p := range models.AllPermissions {
		keys = append(keys, p.Key)
	}
	return keys
}

// RequirePermission 要求当前用户拥有指定权限（在 AuthRequired 之后使用）
func RequirePermission(permission string) gin.HandlerFunc {
	return func(c *gin.Context) {
		roleID, ok := roleIDFromContext(c)
		if !ok {
			c.JSON(http.StatusForbidden, gin.H{"error": "无权限"})
			c.Abort()
			return
		}
		if roleID == models.RoleIDSuperAdmin {
			c.Next()
			return
		}
		ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
		defer cancel()
		perms := getPermissionsByRoleID(ctx, roleID)
		for _, p := range perms {
			if p == permission {
				c.Next()
				return
			}
		}
		c.JSON(http.StatusForbidden, gin.H{"error": "无此操作权限"})
		c.Abort()
	}
}

// GetMyPermissions 返回当前用户权限列表（供前端菜单、按钮显隐）
func GetMyPermissions(c *gin.Context) {
	roleID, ok := roleIDFromContext(c)
	if !ok {
		c.JSON(http.StatusOK, gin.H{"permissions": []string{}})
		return
	}
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
	defer cancel()
	perms := getPermissionsByRoleID(ctx, roleID)
	c.JSON(http.StatusOK, gin.H{"permissions": perms})
}
