package handlers

import (
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"
	"veza-backend-api/internal/services"
)

// CommentHandler gère les opérations sur les commentaires de tracks
type CommentHandler struct {
	commentService *services.CommentService
}

// NewCommentHandler crée un nouveau handler de commentaires
func NewCommentHandler(commentService *services.CommentService) *CommentHandler {
	return &CommentHandler{commentService: commentService}
}

// CreateCommentRequest représente la requête pour créer un commentaire
type CreateCommentRequest struct {
	Content  string `json:"content" binding:"required,min=1,max=5000"`
	ParentID *int64 `json:"parent_id,omitempty"`
}

// UpdateCommentRequest représente la requête pour mettre à jour un commentaire
type UpdateCommentRequest struct {
	Content string `json:"content" binding:"required,min=1,max=5000"`
}

// CreateComment gère la création d'un commentaire sur un track
func (h *CommentHandler) CreateComment(c *gin.Context) {
	userID := c.GetInt64("user_id")
	if userID == 0 {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
		return
	}

	trackIDStr := c.Param("id")
	if trackIDStr == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "track id is required"})
		return
	}

	trackID, err := strconv.ParseInt(trackIDStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid track id"})
		return
	}

	var req CreateCommentRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	comment, err := h.commentService.CreateComment(c.Request.Context(), trackID, userID, req.Content, req.ParentID)
	if err != nil {
		if err.Error() == "track not found" {
			c.JSON(http.StatusNotFound, gin.H{"error": "track not found"})
			return
		}
		if err.Error() == "parent comment not found" {
			c.JSON(http.StatusNotFound, gin.H{"error": "parent comment not found"})
			return
		}
		if err.Error() == "parent comment does not belong to the same track" {
			c.JSON(http.StatusBadRequest, gin.H{"error": "parent comment does not belong to the same track"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusCreated, gin.H{"comment": comment})
}

// GetComments gère la récupération des commentaires d'un track
func (h *CommentHandler) GetComments(c *gin.Context) {
	trackIDStr := c.Param("id")
	if trackIDStr == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "track id is required"})
		return
	}

	trackID, err := strconv.ParseInt(trackIDStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid track id"})
		return
	}

	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))

	if page < 1 {
		page = 1
	}
	if limit < 1 {
		limit = 20
	}
	if limit > 100 {
		limit = 100
	}

	comments, total, err := h.commentService.GetComments(c.Request.Context(), trackID, page, limit)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"comments": comments,
		"total":    total,
		"page":     page,
		"limit":    limit,
	})
}

// UpdateComment gère la mise à jour d'un commentaire
func (h *CommentHandler) UpdateComment(c *gin.Context) {
	userID := c.GetInt64("user_id")
	if userID == 0 {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
		return
	}

	commentIDStr := c.Param("id")
	if commentIDStr == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "comment id is required"})
		return
	}

	commentID, err := strconv.ParseInt(commentIDStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid comment id"})
		return
	}

	var req UpdateCommentRequest
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	comment, err := h.commentService.UpdateComment(c.Request.Context(), commentID, userID, req.Content)
	if err != nil {
		if err.Error() == "comment not found" {
			c.JSON(http.StatusNotFound, gin.H{"error": "comment not found"})
			return
		}
		if err.Error() == "unauthorized: you can only edit your own comments" {
			c.JSON(http.StatusForbidden, gin.H{"error": "unauthorized: you can only edit your own comments"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"comment": comment})
}

// DeleteComment gère la suppression d'un commentaire
func (h *CommentHandler) DeleteComment(c *gin.Context) {
	userID := c.GetInt64("user_id")
	if userID == 0 {
		c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
		return
	}

	commentIDStr := c.Param("id")
	if commentIDStr == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "comment id is required"})
		return
	}

	commentID, err := strconv.ParseInt(commentIDStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid comment id"})
		return
	}

	err = h.commentService.DeleteComment(c.Request.Context(), commentID, userID)
	if err != nil {
		if err.Error() == "comment not found" {
			c.JSON(http.StatusNotFound, gin.H{"error": "comment not found"})
			return
		}
		if err.Error() == "unauthorized: you can only delete your own comments" {
			c.JSON(http.StatusForbidden, gin.H{"error": "unauthorized: you can only delete your own comments"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{"message": "comment deleted successfully"})
}

// GetReplies gère la récupération des réponses d'un commentaire
func (h *CommentHandler) GetReplies(c *gin.Context) {
	parentIDStr := c.Param("id")
	if parentIDStr == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "parent comment id is required"})
		return
	}

	parentID, err := strconv.ParseInt(parentIDStr, 10, 64)
	if err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": "invalid parent comment id"})
		return
	}

	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20"))

	if page < 1 {
		page = 1
	}
	if limit < 1 {
		limit = 20
	}
	if limit > 100 {
		limit = 100
	}

	replies, total, err := h.commentService.GetReplies(c.Request.Context(), parentID, page, limit)
	if err != nil {
		if err.Error() == "parent comment not found" {
			c.JSON(http.StatusNotFound, gin.H{"error": "parent comment not found"})
			return
		}
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"replies": replies,
		"total":   total,
		"page":    page,
		"limit":   limit,
	})
}

