package router

import (
	"net/http"
	"strings"

	"github.com/atlasos/calypso/internal/auth"
	"github.com/atlasos/calypso/internal/common/database"
	"github.com/atlasos/calypso/internal/iam"
	"github.com/gin-gonic/gin"
)

// authMiddleware validates JWT tokens and sets user context
func authMiddleware(authHandler *auth.Handler) gin.HandlerFunc {
	return func(c *gin.Context) {
		var token string

		// Try to extract token from Authorization header first
		authHeader := c.GetHeader("Authorization")
		if authHeader != "" {
			// Parse Bearer token
			parts := strings.SplitN(authHeader, " ", 2)
			if len(parts) == 2 && parts[0] == "Bearer" {
				token = parts[1]
			}
		}

		// If no token from header, try query parameter (for WebSocket)
		if token == "" {
			token = c.Query("token")
		}

		// If still no token, return error
		if token == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "missing authorization token"})
			c.Abort()
			return
		}

		// Validate token and get user
		user, err := authHandler.ValidateToken(token)
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid or expired token"})
			c.Abort()
			return
		}

		// Load user roles and permissions from database
		// We need to get the DB from the auth handler's context
		// For now, we'll load them in the permission middleware instead

		// Set user in context
		c.Set("user", user)
		c.Set("user_id", user.ID)
		c.Set("username", user.Username)

		c.Next()
	}
}

// requireRole creates middleware that requires a specific role
func requireRole(roleName string) gin.HandlerFunc {
	return func(c *gin.Context) {
		user, exists := c.Get("user")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "authentication required"})
			c.Abort()
			return
		}

		authUser, ok := user.(*iam.User)
		if !ok {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user context"})
			c.Abort()
			return
		}

		// Load roles if not already loaded
		if len(authUser.Roles) == 0 {
			// Get DB from context (set by router)
			db, exists := c.Get("db")
			if exists {
				if dbConn, ok := db.(*database.DB); ok {
					roles, err := iam.GetUserRoles(dbConn, authUser.ID)
					if err == nil {
						authUser.Roles = roles
					}
				}
			}
		}

		// Check if user has the required role
		hasRole := false
		for _, role := range authUser.Roles {
			if role == roleName {
				hasRole = true
				break
			}
		}

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

		c.Next()
	}
}

// requirePermission creates middleware that requires a specific permission
func requirePermission(resource, action string) gin.HandlerFunc {
	return func(c *gin.Context) {
		user, exists := c.Get("user")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "authentication required"})
			c.Abort()
			return
		}

		authUser, ok := user.(*iam.User)
		if !ok {
			c.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user context"})
			c.Abort()
			return
		}

		// Load permissions if not already loaded
		if len(authUser.Permissions) == 0 {
			// Get DB from context (set by router)
			db, exists := c.Get("db")
			if exists {
				if dbConn, ok := db.(*database.DB); ok {
					permissions, err := iam.GetUserPermissions(dbConn, authUser.ID)
					if err == nil {
						authUser.Permissions = permissions
					}
				}
			}
		}

		// Check if user has the required permission
		permissionName := resource + ":" + action
		hasPermission := false
		for _, perm := range authUser.Permissions {
			if perm == permissionName {
				hasPermission = true
				break
			}
		}

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

		c.Next()
	}
}

