package api

import (
	"context"
	"database/sql"
	"encoding/json"

	"github.com/gin-gonic/gin"

	"github.com/rycroftapparel/workpulse-api/internal/httpapi"
	"github.com/rycroftapparel/workpulse-api/internal/permissions"
)

func roleFromContext(c *gin.Context) string {
	roleVal, _ := c.Get("role")
	r, _ := roleVal.(string)
	return r
}

func permsFromContext(c *gin.Context) map[string]bool {
	v, ok := c.Get("permissions")
	if !ok {
		return nil
	}
	p, _ := v.(map[string]bool)
	return p
}

func (s *Server) featureAllowed(c *gin.Context, key string) bool {
	if roleFromContext(c) == "superadmin" {
		return true
	}
	return permissions.Allowed(permsFromContext(c), key)
}

func (s *Server) loadUserPermissions(ctx context.Context, userID uint64, role string) (map[string]bool, error) {
	if role == "superadmin" {
		return permissions.AllEnabled(), nil
	}
	var raw []byte
	err := s.DB.QueryRowContext(ctx, `SELECT permissions FROM users WHERE id = $1`, userID).Scan(&raw)
	if err == sql.ErrNoRows {
		return permissions.DefaultUser(), nil
	}
	if err != nil {
		return nil, err
	}
	if raw == nil {
		return permissions.Normalize(role, nil), nil
	}
	return permissions.Normalize(role, raw), nil
}

func (s *Server) requireFeature(key string) gin.HandlerFunc {
	return func(c *gin.Context) {
		if s.featureAllowed(c, key) {
			c.Next()
			return
		}
		c.JSON(403, httpapi.Fail("forbidden", "Anda tidak memiliki akses ke fitur ini."))
		c.Abort()
	}
}

func permissionsForResponse(perms map[string]bool) gin.H {
	out := gin.H{}
	for _, k := range permissions.Keys {
		out[k] = perms[k]
	}
	return out
}

func parsePermissionsBody(role string, raw json.RawMessage) (map[string]bool, []byte, error) {
	if len(raw) == 0 {
		p := permissions.Normalize(role, nil)
		b, err := permissions.ToJSON(p)
		return p, b, err
	}
	var m map[string]bool
	if err := json.Unmarshal(raw, &m); err != nil {
		return nil, nil, err
	}
	b, p, err := permissions.FromClientMap(role, m)
	return p, b, err
}
