package middlewares

import (
	"os"
	"strings"

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

// AdminApiAuth protege /api/v2. Acepta dos tipos de credencial:
//  1. ADMIN_API_KEY de entorno — llave maestra, acceso total, la que ya usan
//     las integraciones existentes (no se retira para no romperlas).
//  2. Una ApiKey emitida desde /app/api-keys — token propio, hasheado en DB,
//     restringida a una IP/CIDR obligatoria y a los scopes que se le hayan
//     habilitado. RequireScope() más adelante en la cadena decide si esa
//     llave puede usar el grupo de endpoints puntual.
func AdminApiAuth() fiber.Handler {
	return func(c *fiber.Ctx) error {
		token := ""
		auth := c.Get("Authorization")
		if strings.HasPrefix(auth, "Bearer ") {
			token = auth[7:]
		}
		if token == "" {
			token = c.Get("X-API-Key")
		}
		if token == "" {
			return c.Status(401).JSON(fiber.Map{"error": "unauthorized"})
		}

		if masterKey := os.Getenv("ADMIN_API_KEY"); masterKey != "" && token == masterKey {
			c.Locals("api_key_master", true)
			return c.Next()
		}

		key, err := models.FindApiKeyActivaByToken(token)
		if err != nil {
			return c.Status(401).JSON(fiber.Map{"error": "unauthorized"})
		}
		if !key.IPValida(c.IP()) {
			return c.Status(403).JSON(fiber.Map{"error": "IP no autorizada para esta API key"})
		}

		go models.RegistrarUsoApiKey(key.ID, c.IP())
		c.Locals("api_key", key)
		return c.Next()
	}
}

// RequireScope gatea un grupo de rutas a un scope puntual. La llave maestra
// (ADMIN_API_KEY de entorno) siempre pasa; una ApiKey scoped solo pasa si
// tiene ese scope habilitado.
func RequireScope(scope string) fiber.Handler {
	return func(c *fiber.Ctx) error {
		if master, _ := c.Locals("api_key_master").(bool); master {
			return c.Next()
		}
		key, ok := c.Locals("api_key").(*models.ApiKey)
		if !ok || key == nil || !key.TieneScope(scope) {
			return c.Status(403).JSON(fiber.Map{"error": "Esta API key no tiene el scope '" + scope + "'"})
		}
		return c.Next()
	}
}
