package handlers

import (
	"net/http"
	"time"

	"veza-backend-api/internal/models"
	"veza-backend-api/internal/services"

	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
)

// LoginRequest représente la requête de connexion
type LoginRequest struct {
	Email    string `json:"email" binding:"required,email"`
	Password string `json:"password" binding:"required,min=6"`
}

// RegisterRequest représente la requête d'inscription
type RegisterRequest struct {
	Username  string `json:"username" binding:"required,min=3,max=50"`
	Email     string `json:"email" binding:"required,email"`
	Password  string `json:"password" binding:"required,min=6"`
	FirstName string `json:"firstName"`
	LastName  string `json:"lastName"`
}

// RefreshTokenRequest représente la requête de refresh token
type RefreshTokenRequest struct {
	RefreshToken string `json:"refresh_token" binding:"required"`
}

// AuthResponse représente la réponse d'authentification
type AuthResponse struct {
	AccessToken  string      `json:"access_token"`
	RefreshToken string      `json:"refresh_token"`
	User         models.User `json:"user"`
}

// Login gère la connexion des utilisateurs
// T0203: Intègre création de session après login avec IP et User-Agent
func Login(authService *services.AuthService, sessionService *services.SessionService, logger *zap.Logger) gin.HandlerFunc {
	return func(c *gin.Context) {
		var req LoginRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		user, tokens, err := authService.Login(req.Email, req.Password, false)
		if err != nil {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
			return
		}

		// T0203: Créer session après login réussi
		// Extraire IP address et User-Agent
		ipAddress := c.ClientIP()
		userAgent := c.GetHeader("User-Agent")
		if userAgent == "" {
			userAgent = "Unknown"
		}
		
		// Définir expiration session (30 jours)
		expiresAt := time.Now().Add(30 * 24 * time.Hour)
		
		// Créer la session (ne pas faire échouer le login si la création échoue)
		if sessionService != nil {
			// Calculer la durée restante
			expiresIn := time.Until(expiresAt)
			
			sessionReq := &services.SessionCreateRequest{
				UserID:    user.ID,
				Token:     tokens.AccessToken,
				IPAddress: ipAddress,
				UserAgent: userAgent,
				ExpiresIn: expiresIn,
			}
			
			if _, err := sessionService.CreateSession(c.Request.Context(), sessionReq); err != nil {
				// Log l'erreur mais ne pas faire échouer le login
				if logger != nil {
					logger.Warn("Failed to create session after login",
						zap.String("user_id", user.ID.String()),
						zap.String("ip_address", ipAddress),
						zap.Error(err),
					)
				}
			}
		}

		c.JSON(http.StatusOK, AuthResponse{
			AccessToken:  tokens.AccessToken,
			RefreshToken: tokens.RefreshToken,
			User:         *user,
		})
	}
}

// Register gère l'inscription des utilisateurs
func Register(authService *services.AuthService) gin.HandlerFunc {
	return func(c *gin.Context) {
		var req RegisterRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		user, tokens, err := authService.Register(req.Email, req.Password)
		if err != nil {
			// Handle different error types appropriately
			switch {
			case services.IsUserAlreadyExistsError(err):
				c.JSON(http.StatusConflict, gin.H{"error": "User already exists"})
			case services.IsInvalidEmail(err):
				c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid email format"})
			case services.IsWeakPassword(err):
				c.JSON(http.StatusBadRequest, gin.H{"error": "Password does not meet requirements"})
			default:
				// Log the actual error for debugging
				c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create user"})
			}
			return
		}

		c.JSON(http.StatusCreated, AuthResponse{
			AccessToken:  tokens.AccessToken,
			RefreshToken: tokens.RefreshToken,
			User:         *user,
		})
	}
}

// RefreshToken gère le refresh des tokens
// TODO: Implémenter RefreshToken dans AuthService
/* func RefreshToken(authService *services.AuthService) gin.HandlerFunc {
	return func(c *gin.Context) {
		var req RefreshTokenRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		// tokens, err := authService.RefreshToken(req.RefreshToken)
		// if err != nil {
		// 	c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid refresh token"})
		// 	return
		// }

		c.JSON(http.StatusOK, gin.H{
			"message": "RefreshToken not yet implemented",
		})
	}
}*/

// Logout gère la déconnexion des utilisateurs
// TODO: Implémenter Logout dans AuthService
/* func Logout(authService *services.AuthService) gin.HandlerFunc {
	return func(c *gin.Context) {
		userID, exists := c.Get("user_id")
		if !exists {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "User not authenticated"})
			return
		}

		// err := authService.Logout(userID.(string))
		// if err != nil {
		// 	c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to logout"})
		// 	return
		// }

		c.JSON(http.StatusOK, gin.H{"message": "Logged out successfully"})
	}
}*/
