package middlewares

import (
	"fmt"
	"sort"
	"strings"

	"github.com/gofiber/fiber/v2"
	"github.com/sujit-baniya/fiber-boilerplate/pkg/auth"
	"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
)

func MenuMiddleware(c *fiber.Ctx) error {
	// Verificar si el usuario está logueado
	if !auth.IsLoggedIn(c) {
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error":   true,
			"message": "Usuario no autenticado",
		})
	}

	// Obtener los datos del usuario autenticado
	user, err := auth.User(c)
	if err != nil {
		// Si ocurre un error al obtener el usuario, finalizar la solicitud
		fmt.Printf("Error al obtener usuario: %v\n", err)
		return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
			"error":   true,
			"message": "Usuario no válido o sesión expirada",
		})
	}

	// Buscar los módulos y submódulos del usuario
	userModules, err := models.FindUserByID(user.ID)
	if err != nil {
		fmt.Printf("Error al buscar datos del usuario: %v\n", err)
		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
			"error":   true,
			"message": "Error al obtener datos del usuario",
		})
	}

	// Organizar los módulos y submódulos
	moduleMap := make(map[string][]map[string]string)

	for _, submodule := range userModules.Role.Submodules {
		// Recuperar el nombre del módulo
		moduleName := submodule.Module.Title
		// Crear un mapa para cada submódulo que contenga el título y la URL
		submoduleData := map[string]string{
			"title": submodule.Title,
			"url":   submodule.Url, // Suponiendo que el submódulo tiene un campo `URL`
		}
		// Agregar el submódulo a la lista correspondiente del módulo
		moduleMap[moduleName] = append(moduleMap[moduleName], submoduleData)
	}

	// Ordenar los módulos alfabéticamente
	var sortedModules []string
	for module := range moduleMap {
		sortedModules = append(sortedModules, module)
	}
	sort.Strings(sortedModules)

	// Ordenar los submódulos de cada módulo alfabéticamente
	for _, moduleName := range sortedModules {
		// Ordenar los submódulos alfabéticamente por título
		sort.Slice(moduleMap[moduleName], func(i, j int) bool {
			return moduleMap[moduleName][i]["title"] < moduleMap[moduleName][j]["title"]
		})
	}
	c.Locals("userModules", moduleMap)

	// Obtener un array solo con las URLs
	var urls []string
	for _, submodules := range moduleMap {
		for _, submoduleData := range submodules {
			urls = append(urls, submoduleData["url"])
		}
	}

	// Opcional: adjuntar la lista de URLs al contexto
	c.Locals("urls", urls)

	// Los administradores tienen acceso a todas las rutas
	if user.IsAdmin {
		return c.Next()
	}

	// Verificar si la URL de la solicitud está en la lista de URLs permitidas
	requestURL := c.Path()

	// Obtener el índice del último '/' en la URL de la solicitud
	lastSlashIndex := strings.LastIndex(requestURL, "/")
	if lastSlashIndex != -1 {
		// Obtener solo la parte de la URL después del último '/'
		requestURL = requestURL[lastSlashIndex+1:]
	}

	// Verificar si la URL modificada está en la lista de URLs permitidas
	urlAllowed := false
	for _, url := range urls {
		// Comparar solo la parte de la URL después del último '/'
		if requestURL == url[strings.LastIndex(url, "/")+1:] {
			urlAllowed = true
			break
		}
	}

	// Si la URL no está permitida, devolver un error
	if !urlAllowed {
		return c.Status(fiber.StatusForbidden).JSON(fiber.Map{
			"error":   true,
			"message": "Acceso no permitido a esta ruta",
		})
	}

	// Continuar con la siguiente función de middleware o manejador
	return c.Next()
}
