package handlers

import (
	"net/http"
	"strconv"

	"veza-backend-api/internal/core/social"
	"veza-backend-api/internal/utils"

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

// SocialHandler gère les opérations sociales
type SocialHandler struct {
	service       social.SocialService
	commonHandler *CommonHandler
}

// NewSocialHandler crée une nouvelle instance de SocialHandler
func NewSocialHandler(service social.SocialService, logger *zap.Logger) *SocialHandler {
	return &SocialHandler{
		service:       service,
		commonHandler: NewCommonHandler(logger),
	}
}

// NewSocialHandlerWithInterface crée une nouvelle instance de SocialHandler avec une interface (pour les tests)
func NewSocialHandlerWithInterface(service social.SocialService, logger *zap.Logger) *SocialHandler {
	return &SocialHandler{
		service:       service,
		commonHandler: NewCommonHandler(logger),
	}
}

// CreatePostRequest DTO pour la création de post
// GO-013: Validation améliorée avec tags go-validator
// MOD-P1-001: Ajout tags validate pour validation systématique
type CreatePostRequest struct {
	Content     string            `json:"content" binding:"required,min=1,max=5000" validate:"required,min=1,max=5000"`
	Attachments map[string]string `json:"attachments" validate:"omitempty"` // track_id, playlist_id (UUID strings)
}

// CreatePost crée un post
// GO-013: Utilise validator centralisé pour validation améliorée
// P0: JSON Hardening - Utilise BindAndValidateJSON pour une gestion robuste des erreurs
func (h *SocialHandler) CreatePost(c *gin.Context) {
	userID, ok := GetUserIDUUID(c)
	if !ok {
		return // Erreur déjà envoyée par GetUserIDUUID
	}

	var req CreatePostRequest
	if appErr := h.commonHandler.BindAndValidateJSON(c, &req); appErr != nil {
		RespondWithAppError(c, appErr)
		return
	}

	// BE-SEC-009: Sanitize user inputs to prevent XSS and injection attacks
	req.Content = utils.SanitizeText(req.Content, 5000)

	attachments := make(map[string]uuid.UUID)
	for k, v := range req.Attachments {
		if id, err := uuid.Parse(v); err == nil {
			attachments[k] = id
		}
	}

	post, err := h.service.CreatePost(c.Request.Context(), userID, req.Content, attachments)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create post"})
		return
	}

	RespondSuccess(c, http.StatusCreated, post)
}

// ToggleLikeRequest DTO pour liker
// GO-013: Validation améliorée avec tags go-validator
// MOD-P1-001: Ajout tags validate pour validation systématique
type ToggleLikeRequest struct {
	TargetID   string `json:"target_id" binding:"required,uuid" validate:"required,uuid"`
	TargetType string `json:"target_type" binding:"required,oneof=post track playlist" validate:"required,oneof=post track playlist"`
}

// ToggleLike like ou unlike un objet
// GO-013: Utilise validator centralisé pour validation améliorée
// P0: JSON Hardening - Utilise BindAndValidateJSON pour une gestion robuste des erreurs
func (h *SocialHandler) ToggleLike(c *gin.Context) {
	userID, ok := GetUserIDUUID(c)
	if !ok {
		return // Erreur déjà envoyée par GetUserIDUUID
	}

	var req ToggleLikeRequest
	if appErr := h.commonHandler.BindAndValidateJSON(c, &req); appErr != nil {
		RespondWithAppError(c, appErr)
		return
	}

	// UUID validation déjà fait par binding tag, mais on garde le parse pour compatibilité
	targetID, err := uuid.Parse(req.TargetID)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid target_id format"})
		return
	}

	liked, err := h.service.ToggleLike(c.Request.Context(), userID, targetID, req.TargetType)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to toggle like"})
		return
	}

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

// AddCommentRequest DTO pour commenter
// GO-013: Validation améliorée avec tags go-validator
// MOD-P1-001: Ajout tags validate pour validation systématique
type AddCommentRequest struct {
	TargetID   string `json:"target_id" binding:"required,uuid" validate:"required,uuid"`
	TargetType string `json:"target_type" binding:"required,oneof=post track playlist" validate:"required,oneof=post track playlist"`
	Content    string `json:"content" binding:"required,min=1,max=2000" validate:"required,min=1,max=2000"`
}

// AddComment ajoute un commentaire
// GO-013: Utilise validator centralisé pour validation améliorée
// P0: JSON Hardening - Utilise BindAndValidateJSON pour une gestion robuste des erreurs
func (h *SocialHandler) AddComment(c *gin.Context) {
	userID, ok := GetUserIDUUID(c)
	if !ok {
		return // Erreur déjà envoyée par GetUserIDUUID
	}

	var req AddCommentRequest
	if appErr := h.commonHandler.BindAndValidateJSON(c, &req); appErr != nil {
		RespondWithAppError(c, appErr)
		return
	}

	// UUID validation déjà fait par binding tag, mais on garde le parse pour compatibilité
	targetID, err := uuid.Parse(req.TargetID)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid target_id format"})
		return
	}

	comment, err := h.service.AddComment(c.Request.Context(), userID, targetID, req.TargetType, req.Content)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to add comment"})
		return
	}

	RespondSuccess(c, http.StatusCreated, comment)
}

// GetFeed récupère le feed global
func (h *SocialHandler) GetFeed(c *gin.Context) {
	feed, err := h.service.GetGlobalFeed(c.Request.Context(), 20, 0)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get feed"})
		return
	}
	RespondSuccess(c, http.StatusOK, feed)
}

// GetPostsByUser récupère les posts d'un utilisateur spécifique
func (h *SocialHandler) GetPostsByUser(c *gin.Context) {
	userIDStr := c.Param("user_id")
	userID, err := uuid.Parse(userIDStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid user ID"})
		return
	}

	pageParam := c.DefaultQuery("page", "1")
	limitParam := c.DefaultQuery("limit", "20")

	page, err := strconv.Atoi(pageParam)
	if err != nil || page < 1 {
		page = 1
	}

	limit, err := strconv.Atoi(limitParam)
	if err != nil || limit < 1 {
		limit = 20
	}

	offset := (page - 1) * limit

	posts, err := h.service.GetPostsByUser(c.Request.Context(), userID, limit, offset)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get posts"})
		return
	}

	RespondSuccess(c, http.StatusOK, posts)
}
