package middleware

import (
	"net/http"
	"strings"

	"fotbal-club/internal/config"
	"fotbal-club/internal/models"
	"fotbal-club/pkg/utils"

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

// JWTAuth is a middleware that checks for a valid JWT token
func JWTAuth(db *gorm.DB) gin.HandlerFunc {
	return func(c *gin.Context) {
		// Admin token shortcut: if a valid admin access token is provided, set admin role
		if config.AppConfig != nil && config.AppConfig.AdminAccessToken != "" {
			header := c.GetHeader("X-Admin-Token")
			if header != "" && header == config.AppConfig.AdminAccessToken {
				c.Set("userRole", "admin")
				c.Set("user", &models.User{Role: "admin"})
				c.Next()
				return
			}
		}
		authHeader := c.GetHeader("Authorization")
		var tokenString string
		if authHeader != "" {
			// Extract the token from the header (format: "Bearer <token>")
			tokenParts := strings.Split(authHeader, " ")
			if len(tokenParts) == 2 && tokenParts[0] == "Bearer" {
				tokenString = tokenParts[1]
			} else {
				// If header present but malformed, reject early
				c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid authorization header format"})
				c.Abort()
				return
			}
		} else {
			// Fallback: try HttpOnly cookie set by server
			if cookie, err := c.Request.Cookie("auth_token"); err == nil {
				tokenString = cookie.Value
			} else {
				c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header or auth cookie is required"})
				c.Abort()
				return
			}
		}

		claims, err := utils.ParseJWT(tokenString)
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid or expired token"})
			c.Abort()
			return
		}

		// Check if user exists
		var user models.User
		if err := db.First(&user, claims.UserID).Error; err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "User not found"})
			c.Abort()
			return
		}

		// Add user information to the context
		c.Set("user", &user)
		// Also expose parsed JWT claims for helpers/utilities
		c.Set("claims", claims)
		c.Set("userID", user.ID)
		c.Set("userRole", user.Role)

		c.Next()
	}
}

// DevBypass checks for special dev header and grants admin role when not in production
func DevBypass() gin.HandlerFunc {
	return func(c *gin.Context) {
		if config.AppConfig != nil && config.AppConfig.AppEnv != "production" {
			if strings.ToLower(c.GetHeader("X-Dev-Admin")) == "true" {
				c.Set("userRole", "admin")
				// set a placeholder user
				c.Set("user", &models.User{Role: "admin"})
				c.Next()
				return
			}
		}
		c.Next()
	}
}

// RoleAuth is a middleware that checks if the user has the required role
// Admin always has access. Editor has access to content creation (articles, activities).
func RoleAuth(requiredRole string) gin.HandlerFunc {
	return func(c *gin.Context) {
		userRole, exists := c.Get("userRole")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "User role not found"})
			c.Abort()
			return
		}

		// Admin always has full access
		if userRole == "admin" {
			c.Next()
			return
		}

		// Check if user has the required role
		if userRole != requiredRole {
			c.JSON(http.StatusForbidden, gin.H{"error": "Insufficient permissions"})
			c.Abort()
			return
		}

		c.Next()
	}
}
