package roles

import (
	"fmt"
	"server/internal/tokens"
	"strings"

	"github.com/gofiber/fiber/v3"
	"gorm.io/gorm"
)

type Permission int

type Role struct {
	Name        string
	Permissions Permission
}

const (
	SuperAdminPermission     Permission = 0b1111111111111111
	AdminPermission          Permission = 0b0111111111111111
	ManagerPermission        Permission = 0b0010111111111111
	ContentCreatorPermission Permission = 0b0001111111111111
	UserPermission           Permission = 0b0000000000000011
	GuestPermission          Permission = 0b0000000000000001
)

var Roles = []Role{
	{"superadmin", SuperAdminPermission},
	{"admin", AdminPermission},
	{"manager", ManagerPermission},
	{"content_creator", ContentCreatorPermission},
	{"user", UserPermission},
	{"guest", GuestPermission},
}

var Endpoints map[string]int

func init() {
	Endpoints = make(map[string]int)
}

func RegisterEndpoint(key string, permission int) {
	Endpoints[key] = permission
}

// RequireEndpointPermission enforces permission mapping defined in role config.
// If the endpoint is not configured, or mapped to "*", it allows the request.
func RequireEndpointPermission(dbConn *gorm.DB, tokenService *tokens.TockenService) fiber.Handler {
	return func(c fiber.Ctx) error {
		fmt.Printf("Checking permissions for %s%s\n", strings.TrimSpace(c.Method()), strings.TrimSpace(c.Path()))
		perm := Endpoints[strings.TrimSpace(c.Method())+strings.TrimSpace(c.Path())]
		if perm == 0 {
			return c.Next()
		}

		tokenString := c.Get("Auth-Token")
		if tokenString == "" {
			return fiber.NewError(fiber.StatusUnauthorized, "missing token header")
		}

		claims, err := tokenService.ValidateAccessToken(tokenString)
		if err != nil {
			return fiber.NewError(fiber.StatusUnauthorized, err.Error())
		}
		c.Locals("authClaims", claims)

		// user need to have at least one role that satisfies the permission requirement
		if claims.Role == "" {
			return fiber.NewError(fiber.StatusForbidden, "insufficient permissions")
		}

		return c.Next()
	}
}
