package middleware

import (
	"net/http"
	"project-dashboard/api/utils"
	"project-dashboard/models"
	"strings"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
)

type Claims struct {
	UserID uint   `json:"user_id"`
	Email  string `json:"email"`
	Role   string `json:"role"`
	jwt.StandardClaims
}

var jwtSecret = []byte("your-secret-key") // In production, use environment variable

// GenerateToken generates a JWT token for the user
func GenerateToken(user *models.User) (string, error) {
	claims := Claims{
		UserID: user.ID,
		Email:  user.Email,
		Role:   user.Role,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: 15000, // 24 hours
			Issuer:    "project-dashboard",
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString(jwtSecret)
}

// AuthMiddleware validates JWT token
func AuthMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		authHeader := c.GetHeader("Authorization")
		if authHeader == "" {
			utils.ErrorResponse(c, http.StatusUnauthorized, "Authorization header required")
			c.Abort()
			return
		}

		tokenString := strings.TrimPrefix(authHeader, "Bearer ")
		if tokenString == authHeader {
			utils.ErrorResponse(c, http.StatusUnauthorized, "Invalid authorization header format")
			c.Abort()
			return
		}

		claims := &Claims{}
		token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
			return jwtSecret, nil
		})

		if err != nil || !token.Valid {
			utils.ErrorResponse(c, http.StatusUnauthorized, "Invalid token")
			c.Abort()
			return
		}

		// Get user from database
		var user models.User
		if err := models.GetDB().First(&user, claims.UserID).Error; err != nil {
			utils.ErrorResponse(c, http.StatusUnauthorized, "User not found")
			c.Abort()
			return
		}

		c.Set("user", &user)
		c.Set("user_id", user.ID)
		c.Next()
	}
}

// AdminMiddleware ensures user has admin role
func AdminMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		user, exists := c.Get("user")
		if !exists {
			utils.ErrorResponse(c, http.StatusUnauthorized, "User not authenticated")
			c.Abort()
			return
		}

		userObj := user.(*models.User)
		if !userObj.IsAdmin() {
			utils.ErrorResponse(c, http.StatusForbidden, "Admin access required")
			c.Abort()
			return
		}

		c.Next()
	}
}

// ManagerMiddleware ensures user has manager role or higher
func ManagerMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		user, exists := c.Get("user")
		if !exists {
			utils.ErrorResponse(c, http.StatusUnauthorized, "User not authenticated")
			c.Abort()
			return
		}

		userObj := user.(*models.User)
		if !userObj.IsManager() {
			utils.ErrorResponse(c, http.StatusForbidden, "Manager access required")
			c.Abort()
			return
		}

		c.Next()
	}
}

// ProjectAccessMiddleware ensures user has access to the project
func ProjectAccessMiddleware() gin.HandlerFunc {
	return func(c *gin.Context) {
		user, exists := c.Get("user")
		if !exists {
			utils.ErrorResponse(c, http.StatusUnauthorized, "User not authenticated")
			c.Abort()
			return
		}

		userObj := user.(*models.User)
		projectID := c.Param("project_id")

		if projectID == "" {
			utils.ErrorResponse(c, http.StatusBadRequest, "Project ID required")
			c.Abort()
			return
		}

		var project models.Project
		if err := models.GetDB().Preload("Members").First(&project, projectID).Error; err != nil {
			utils.ErrorResponse(c, http.StatusNotFound, "Project not found")
			c.Abort()
			return
		}

		// Check if user is owner or member
		if !project.IsOwner(userObj.ID) && !project.HasMember(userObj.ID) {
			utils.ErrorResponse(c, http.StatusForbidden, "Access denied to project")
			c.Abort()
			return
		}

		c.Set("project", &project)
		c.Next()
	}
}
