package handlers

import (
	"context"
	"database/sql"
	"net/http"

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

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

// VerifyEmailRequest represents a request to verify email
type VerifyEmailRequest struct {
	Token string `json:"token" binding:"required"`
}

// ResendVerificationRequest represents a request to resend verification email
// T0186: Requête pour renvoyer l'email de vérification
type ResendVerificationRequest struct {
	Email string `json:"email" binding:"required,email"`
}

// VerifyEmail handles email verification
// T0183: Endpoint pour vérifier le token et marquer l'email comme vérifié
func VerifyEmail(emailVerificationService *services.EmailVerificationService, db *database.Database, logger *zap.Logger) gin.HandlerFunc {
	return func(c *gin.Context) {
		// Étape 2: Extraire token depuis query parameter
		token := c.Query("token")
		if token == "" {
			c.JSON(http.StatusBadRequest, gin.H{"error": "token is required"})
			return
		}

		// Étape 3: Appeler EmailVerificationService.VerifyToken
		userID, err := emailVerificationService.VerifyToken(token)
		if err != nil {
			// Gestion erreurs (token invalide, expiré, déjà utilisé)
			if err.Error() == "invalid token" {
				c.JSON(http.StatusBadRequest, gin.H{"error": "invalid token"})
				return
			}
			if err.Error() == "token expired" {
				c.JSON(http.StatusBadRequest, gin.H{"error": "token expired"})
				return
			}
			if err.Error() == "token already used" {
				c.JSON(http.StatusBadRequest, gin.H{"error": "token already used"})
				return
			}
			c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to verify token"})
			return
		}

		// Étape 4: Mettre à jour user.is_verified = TRUE
		ctx := context.Background()
		_, err = db.ExecContext(ctx, `
			UPDATE users
			SET is_verified = TRUE, updated_at = NOW()
			WHERE id = $1
		`, userID)
		if err != nil {
			logger.Error("Failed to update user email verification status",
				zap.Int64("user_id", userID),
				zap.Error(err),
			)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to update user"})
			return
		}

		logger.Info("Email verified successfully",
			zap.Int64("user_id", userID),
		)

		// Étape 5: Retourner réponse succès
		c.JSON(http.StatusOK, gin.H{
			"message": "Email verified successfully",
			"user_id": userID,
		})
	}
}

// ResendVerificationEmail handles resending verification emails
// T0186: Endpoint pour renvoyer l'email de vérification
func ResendVerificationEmail(
	emailVerificationService *services.EmailVerificationService,
	emailService *services.EmailService,
	db *database.Database,
	logger *zap.Logger,
) gin.HandlerFunc {
	return func(c *gin.Context) {
		// Étape 2: Valider email dans request body
		var req ResendVerificationRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		// Étape 2: Vérifier que l'utilisateur existe
		ctx := context.Background()
		var userID int64
		var isVerified bool
		err := db.QueryRowContext(ctx, `
			SELECT id, is_verified
			FROM users
			WHERE email = $1
		`, req.Email).Scan(&userID, &isVerified)

		if err != nil {
			if err == sql.ErrNoRows {
				logger.Warn("User not found for resend verification",
					zap.String("email", req.Email),
				)
				c.JSON(http.StatusNotFound, gin.H{"error": "user not found"})
				return
			}
			logger.Error("Failed to query user for resend verification",
				zap.String("email", req.Email),
				zap.Error(err),
			)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to check user"})
			return
		}

		// Étape 3: Vérifier que email n'est pas déjà vérifié
		if isVerified {
			logger.Info("Attempt to resend verification for already verified email",
				zap.String("email", req.Email),
				zap.Int64("user_id", userID),
			)
			c.JSON(http.StatusBadRequest, gin.H{"error": "email already verified"})
			return
		}

		// Étape 4: Invalider anciens tokens
		if err := emailVerificationService.InvalidateOldTokens(userID); err != nil {
			logger.Warn("Failed to invalidate old tokens",
				zap.Int64("user_id", userID),
				zap.Error(err),
			)
			// On continue quand même car ce n'est pas bloquant
		}

		// Étape 5: Générer nouveau token
		token, err := emailVerificationService.GenerateToken()
		if err != nil {
			logger.Error("Failed to generate verification token",
				zap.Int64("user_id", userID),
				zap.Error(err),
			)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to generate token"})
			return
		}

		// Étape 5: Stocker le token
		if err := emailVerificationService.StoreToken(userID, token); err != nil {
			logger.Error("Failed to store verification token",
				zap.Int64("user_id", userID),
				zap.Error(err),
			)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to store token"})
			return
		}

		// Étape 5: Envoyer email
		if err := emailService.SendVerificationEmail(req.Email, token); err != nil {
			logger.Error("Failed to send verification email",
				zap.Int64("user_id", userID),
				zap.String("email", req.Email),
				zap.Error(err),
			)
			c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to send email"})
			return
		}

		logger.Info("Verification email resent successfully",
			zap.Int64("user_id", userID),
			zap.String("email", req.Email),
		)

		c.JSON(http.StatusOK, gin.H{"message": "verification email sent"})
	}
}

// CheckEmailVerificationStatus checks if an email is verified
func CheckEmailVerificationStatus(emailService *services.EmailService) 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
		}

		// Get verification status from user
		// This would typically be done by querying the user's email_verified field
		// For now, return a simple response
		c.JSON(http.StatusOK, gin.H{
			"user_id":        userID,
			"email_verified": true, // This should be queried from DB
		})
	}
}
