package handlers

import (
	"mime/multipart"
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"

	apperrors "veza-backend-api/internal/errors"
	"veza-backend-api/internal/models"
	"veza-backend-api/internal/services"
)

// ImageServiceInterface defines the interface for image operations
// This allows for easier testing with mocks
type ImageServiceInterface interface {
	ProcessAvatar(fileHeader *multipart.FileHeader) ([]byte, error)
	GenerateS3Key(userID uuid.UUID) string
	UploadToS3(data []byte, key string) (string, error)
	DeleteFromS3(avatarURL string) error
}

// UserServiceInterfaceForAvatar defines the interface for user operations needed by avatar handler
// This allows for easier testing with mocks
type UserServiceInterfaceForAvatar interface {
	GetByID(userID uuid.UUID) (*models.User, error)
	UpdateAvatarURL(userID uuid.UUID, avatarURL string) error
}

// AvatarHandler handles avatar-related operations
type AvatarHandler struct {
	imageService ImageServiceInterface
	userService  UserServiceInterfaceForAvatar
}

// NewAvatarHandler creates a new AvatarHandler instance
func NewAvatarHandler(imageService *services.ImageService, userService *services.UserService) *AvatarHandler {
	return &AvatarHandler{
		imageService: imageService,
		userService:  userService,
	}
}

// NewAvatarHandlerWithInterface creates a new AvatarHandler with interfaces (for testing)
func NewAvatarHandlerWithInterface(imageService ImageServiceInterface, userService UserServiceInterfaceForAvatar) *AvatarHandler {
	return &AvatarHandler{
		imageService: imageService,
		userService:  userService,
	}
}

// UploadAvatar handles avatar upload
// POST /api/v1/users/:userId/avatar
// BE-API-021: Implement avatar upload endpoint
// T0221: Validates user_id, file format/size, processes image, uploads to S3, and updates DB
func (h *AvatarHandler) UploadAvatar(c *gin.Context) {
	// Récupérer l'ID utilisateur depuis l'URL (peut être "id" ou "userId")
	userIDStr := c.Param("userId")
	if userIDStr == "" {
		userIDStr = c.Param("id")
	}
	userID, err := uuid.Parse(userIDStr)
	if err != nil {
		RespondWithAppError(c, apperrors.NewValidationError("invalid user id"))
		return
	}

	// Vérifier que l'utilisateur est authentifié
	authenticatedUserID, ok := GetUserIDUUID(c)
	if !ok {
		return // Erreur déjà envoyée par GetUserIDUUID
	}

	// Vérifier que l'utilisateur ne peut modifier que son propre avatar
	if userID != authenticatedUserID {
		RespondWithAppError(c, apperrors.NewForbiddenError("cannot update other user's avatar"))
		return
	}

	// Récupérer le fichier
	fileHeader, err := c.FormFile("avatar")
	if err != nil {
		RespondWithAppError(c, apperrors.NewValidationError("no file provided"))
		return
	}

	// Valider et traiter l'image
	resizedImage, err := h.imageService.ProcessAvatar(fileHeader)
	if err != nil {
		RespondWithAppError(c, apperrors.NewValidationError(err.Error()))
		return
	}

	// Générer la clé S3
	s3Key := h.imageService.GenerateS3Key(userID)

	// Upload vers S3 (ou stockage local pour l'instant)
	avatarURL, err := h.imageService.UploadToS3(resizedImage, s3Key)
	if err != nil {
		RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "failed to upload avatar", err))
		return
	}

	// Mettre à jour l'URL de l'avatar dans la DB
	if err := h.userService.UpdateAvatarURL(userID, avatarURL); err != nil {
		RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "failed to update avatar", err))
		return
	}

	RespondSuccess(c, http.StatusOK, gin.H{"avatar_url": avatarURL})
}

// DeleteAvatar handles avatar deletion
// DELETE /api/v1/users/:userId/avatar
// BE-API-022: Implement avatar delete endpoint
// T0222: Validates user_id, deletes file from S3, and sets avatar_url to NULL in DB
func (h *AvatarHandler) DeleteAvatar(c *gin.Context) {
	// Récupérer l'ID utilisateur depuis l'URL (peut être "id" ou "userId")
	userIDStr := c.Param("userId")
	if userIDStr == "" {
		userIDStr = c.Param("id")
	}
	userID, err := uuid.Parse(userIDStr)
	if err != nil {
		RespondWithAppError(c, apperrors.NewValidationError("invalid user id"))
		return
	}

	// Vérifier que l'utilisateur est authentifié
	authenticatedUserID, ok := GetUserIDUUID(c)
	if !ok {
		return // Erreur déjà envoyée par GetUserIDUUID
	}

	// Vérifier que l'utilisateur ne peut supprimer que son propre avatar
	if userID != authenticatedUserID {
		RespondWithAppError(c, apperrors.NewForbiddenError("cannot delete other user's avatar"))
		return
	}

	// Récupérer l'utilisateur actuel pour obtenir l'URL de l'avatar
	user, err := h.userService.GetByID(userID)
	if err != nil {
		RespondWithAppError(c, apperrors.NewNotFoundError("user"))
		return
	}

	// Supprimer le fichier de S3 (ou stockage local) s'il existe
	if user.Avatar != "" {
		if err := h.imageService.DeleteFromS3(user.Avatar); err != nil {
			// Logger l'erreur mais continuer (le fichier peut déjà être supprimé)
			// En production, vous pourriez vouloir utiliser un logger ici
			_ = err
		}
	}

	// Mettre l'URL de l'avatar à une chaîne vide (NULL dans la DB)
	if err := h.userService.UpdateAvatarURL(userID, ""); err != nil {
		RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "failed to delete avatar", err))
		return
	}

	RespondSuccess(c, http.StatusOK, gin.H{"message": "avatar deleted"})
}
