package middleware

import (
	"strings"
	"web-qudo-be/app/database/entity"

	"github.com/gofiber/fiber/v2"
	"github.com/google/uuid"
	"gorm.io/gorm"
)

const (
	ClientKeyHeader  = "X-Client-Key"
	ClientContextKey = "client_id"
)

// excludedPaths contains paths that don't require client key validation
var excludedPaths = []string{
	"/swagger/*",
	"/docs/*",
	"/users/login",
	"/health/*",
	"/clients",
	"/clients/*",
	"*/viewer/*",
	"/bookmarks/test-table",
}

// isPathExcluded checks if the given path should be excluded from client key validation
func isPathExcluded(path string) bool {
	for _, excludedPath := range excludedPaths {
		if strings.HasPrefix(excludedPath, "*") && strings.HasSuffix(excludedPath, "*") {
			// Handle wildcard at both beginning and end (e.g., "*/viewer/*")
			pattern := excludedPath[1 : len(excludedPath)-1] // Remove * from both ends
			if strings.Contains(path, pattern) {
				return true
			}
		} else if strings.HasPrefix(excludedPath, "*") {
			// Handle wildcard at the beginning
			if strings.HasSuffix(path, excludedPath[1:]) {
				return true
			}
		} else if strings.HasSuffix(excludedPath, "*") {
			// Handle wildcard at the end
			prefix := excludedPath[:len(excludedPath)-1]
			if strings.HasPrefix(path, prefix) {
				return true
			}
		} else {
			// Exact match
			if path == excludedPath {
				return true
			}
		}
	}
	return false
}

// ClientMiddleware extracts and validates the Client Key from request headers
func ClientMiddleware(db *gorm.DB) fiber.Handler {
	return func(c *fiber.Ctx) error {
		// Check if path should be excluded from client key validation
		if isPathExcluded(c.Path()) {
			return c.Next()
		}

		// Extract Client Key from header
		clientKey := c.Get(ClientKeyHeader)

		if clientKey == "" {
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
				"success":  false,
				"code":     400,
				"messages": []string{"Client Key is required in header: " + ClientKeyHeader},
			})
		}

		// Parse UUID
		clientUUID, err := uuid.Parse(clientKey)
		if err != nil {
			return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
				"success":  false,
				"code":     400,
				"messages": []string{"Invalid Client Key format"},
			})
		}

		// Validate client exists and is active
		var client entity.Clients
		if err := db.Where("id = ? AND is_active = ?", clientUUID, true).First(&client).Error; err != nil {
			if err == gorm.ErrRecordNotFound {
				return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
					"success":  false,
					"code":     401,
					"messages": []string{"Invalid or inactive Client Key"},
				})
			}
			return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
				"success":  false,
				"code":     500,
				"messages": []string{"Error validating Client Key"},
			})
		}

		// Store client ID in context for use in handlers
		c.Locals(ClientContextKey, clientUUID)

		return c.Next()
	}
}

// GetClientID retrieves the client ID from the context
func GetClientID(c *fiber.Ctx) *uuid.UUID {
	if clientID, ok := c.Locals(ClientContextKey).(uuid.UUID); ok {
		return &clientID
	}
	return nil
}

// AddExcludedPath adds a new path to the excluded paths list
func AddExcludedPath(path string) {
	excludedPaths = append(excludedPaths, path)
}

// GetExcludedPaths returns the current list of excluded paths
func GetExcludedPaths() []string {
	return excludedPaths
}
