package handlers import ( "net/http" "github.com/gin-gonic/gin" "github.com/google/uuid" "go.uber.org/zap" apperrors "veza-backend-api/internal/errors" "veza-backend-api/internal/services" ) // QueueHandler handles queue HTTP requests type QueueHandler struct { queueService *services.QueueService logger *zap.Logger } // NewQueueHandler creates a new QueueHandler func NewQueueHandler(queueService *services.QueueService, logger *zap.Logger) *QueueHandler { return &QueueHandler{queueService: queueService, logger: logger} } // GetQueue returns the user's queue // @Summary Get user playback queue // @Description Returns the authenticated user's persistent playback queue with all items in position order // @Tags Queue // @Accept json // @Produce json // @Security BearerAuth // @Success 200 {object} APIResponse{data=object{queue=object,items=[]object}} "Queue + items" // @Failure 401 {object} APIResponse "Unauthorized" // @Failure 500 {object} APIResponse "Internal Error" // @Router /queue [get] func (h *QueueHandler) GetQueue(c *gin.Context) { userID, ok := GetUserIDUUID(c) if !ok { return } q, err := h.queueService.GetOrCreateQueue(c.Request.Context(), userID) if err != nil { RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to get queue", err)) return } RespondSuccess(c, http.StatusOK, gin.H{ "queue": q, "items": q.Items, }) } // UpdateQueue updates the user's queue // @Summary Update user playback queue // @Description Updates the authenticated user's queue state (current track / position / playback flags / item order) // @Tags Queue // @Accept json // @Produce json // @Security BearerAuth // @Param request body services.UpdateQueueRequest true "Queue update payload" // @Success 200 {object} APIResponse{data=object{queue=object,items=[]object}} "Updated queue" // @Failure 400 {object} APIResponse "Validation error" // @Failure 401 {object} APIResponse "Unauthorized" // @Failure 500 {object} APIResponse "Internal Error" // @Router /queue [put] func (h *QueueHandler) UpdateQueue(c *gin.Context) { userID, ok := GetUserIDUUID(c) if !ok { return } var req services.UpdateQueueRequest if err := c.ShouldBindJSON(&req); err != nil { RespondWithAppError(c, apperrors.NewValidationError("invalid request body")) return } q, err := h.queueService.UpdateQueue(c.Request.Context(), userID, &req) if err != nil { RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to update queue", err)) return } RespondSuccess(c, http.StatusOK, gin.H{ "queue": q, "items": q.Items, }) } // AddQueueItemRequest represents the request body for adding an item type AddQueueItemRequest struct { TrackID uuid.UUID `json:"track_id" binding:"required"` } // AddQueueItem adds a track to the queue // @Summary Add track to queue // @Description Appends a track to the authenticated user's playback queue // @Tags Queue // @Accept json // @Produce json // @Security BearerAuth // @Param request body AddQueueItemRequest true "Track to enqueue" // @Success 201 {object} APIResponse{data=object{item=object}} "Created queue item" // @Failure 400 {object} APIResponse "Validation error" // @Failure 401 {object} APIResponse "Unauthorized" // @Failure 500 {object} APIResponse "Internal Error" // @Router /queue/items [post] func (h *QueueHandler) AddQueueItem(c *gin.Context) { userID, ok := GetUserIDUUID(c) if !ok { return } var req AddQueueItemRequest if err := c.ShouldBindJSON(&req); err != nil { RespondWithAppError(c, apperrors.NewValidationError("track_id is required")) return } item, err := h.queueService.AddToQueue(c.Request.Context(), userID, req.TrackID) if err != nil { RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to add to queue", err)) return } RespondSuccess(c, http.StatusCreated, gin.H{"item": item}) } // RemoveQueueItem removes an item from the queue // @Summary Remove queue item // @Description Removes a single item from the authenticated user's playback queue by item ID // @Tags Queue // @Accept json // @Produce json // @Security BearerAuth // @Param id path string true "Queue item ID (UUID)" // @Success 200 {object} APIResponse{data=object{message=string}} "Item removed" // @Failure 400 {object} APIResponse "Invalid item ID" // @Failure 401 {object} APIResponse "Unauthorized" // @Failure 404 {object} APIResponse "Queue item not found" // @Router /queue/items/{id} [delete] func (h *QueueHandler) RemoveQueueItem(c *gin.Context) { userID, ok := GetUserIDUUID(c) if !ok { return } id, err := uuid.Parse(c.Param("id")) if err != nil { RespondWithAppError(c, apperrors.NewValidationError("invalid item ID")) return } if err := h.queueService.RemoveFromQueue(c.Request.Context(), userID, id); err != nil { RespondWithAppError(c, apperrors.NewNotFoundError("queue item not found")) return } RespondSuccess(c, http.StatusOK, gin.H{"message": "item removed"}) } // ClearQueue removes all items from the queue // @Summary Clear queue // @Description Removes every item from the authenticated user's playback queue // @Tags Queue // @Accept json // @Produce json // @Security BearerAuth // @Success 200 {object} APIResponse{data=object{message=string}} "Queue cleared" // @Failure 401 {object} APIResponse "Unauthorized" // @Failure 500 {object} APIResponse "Internal Error" // @Router /queue [delete] func (h *QueueHandler) ClearQueue(c *gin.Context) { userID, ok := GetUserIDUUID(c) if !ok { return } if err := h.queueService.ClearQueue(c.Request.Context(), userID); err != nil { RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to clear queue", err)) return } RespondSuccess(c, http.StatusOK, gin.H{"message": "queue cleared"}) }