package middleware

import (
	"context"
	"net/http"

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

// RoleChecker définit l'interface minimale pour vérifier les rôles et permissions
// Permet d'utiliser des mocks dans les tests sans modifier la signature publique
type RoleChecker interface {
	HasRole(ctx context.Context, userID int64, roleName string) (bool, error)
	HasPermission(ctx context.Context, userID int64, resource, action string) (bool, error)
}

// RequireRole crée un middleware qui exige qu'un utilisateur ait un rôle spécifique
func RequireRole(roleService RoleChecker, roleName string) gin.HandlerFunc {
	return func(c *gin.Context) {
		// Récupérer user_id du contexte (doit être défini par AuthMiddleware)
		userIDInterface, exists := c.Get("user_id")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
			c.Abort()
			return
		}

		// Convertir user_id en int64
		var userID int64
		switch v := userIDInterface.(type) {
		case int64:
			userID = v
		case int:
			userID = int64(v)
		case float64:
			userID = int64(v)
		default:
			c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid user id type"})
			c.Abort()
			return
		}

		// Vérifier si l'utilisateur a le rôle requis
		hasRole, err := roleService.HasRole(c.Request.Context(), userID, roleName)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to check role"})
			c.Abort()
			return
		}

		if !hasRole {
			c.JSON(http.StatusForbidden, gin.H{"error": "insufficient permissions"})
			c.Abort()
			return
		}

		c.Next()
	}
}

// RequirePermission crée un middleware qui exige qu'un utilisateur ait une permission spécifique
func RequirePermission(roleService RoleChecker, resource, action string) gin.HandlerFunc {
	return func(c *gin.Context) {
		// Récupérer user_id du contexte (doit être défini par AuthMiddleware)
		userIDInterface, exists := c.Get("user_id")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
			c.Abort()
			return
		}

		// Convertir user_id en int64
		var userID int64
		switch v := userIDInterface.(type) {
		case int64:
			userID = v
		case int:
			userID = int64(v)
		case float64:
			userID = int64(v)
		default:
			c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid user id type"})
			c.Abort()
			return
		}

		// Vérifier si l'utilisateur a la permission requise
		hasPermission, err := roleService.HasPermission(c.Request.Context(), userID, resource, action)
		if err != nil {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to check permission"})
			c.Abort()
			return
		}

		if !hasPermission {
			c.JSON(http.StatusForbidden, gin.H{"error": "insufficient permissions"})
			c.Abort()
			return
		}

		c.Next()
	}
}
