//go:build ignore // +build ignore // NOTE: Disabled (build ignore). Chat server removed; re-enable when chat service is reimplemented. package handlers import ( "net/http" "strconv" "github.com/gin-gonic/gin" "github.com/google/uuid" "go.uber.org/zap" "veza-backend-api/internal/services" ) // ChatHandlers handles chat-related API endpoints type ChatHandlers struct { chatService *services.ChatService logger *zap.Logger } // NewChatHandlers creates new chat handlers func NewChatHandlers(chatService *services.ChatService, logger *zap.Logger) *ChatHandlers { return &ChatHandlers{ chatService: chatService, logger: logger, } } // InitChatHandlers initializes chat handlers func InitChatHandlers(chatService *services.ChatService, logger *zap.Logger) { handlers := NewChatHandlers(chatService, logger) // Store handlers globally for route registration ChatHandlersInstance = handlers } // ChatHandlersInstance holds the global chat handlers instance var ChatHandlersInstance *ChatHandlers // CreateMessage creates a new message in a room func (h *ChatHandlers) CreateMessage(c *gin.Context) { userID := c.GetInt64("user_id") roomID, err := strconv.ParseInt(c.Param("room_id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"}) return } var req struct { Content string `json:"content" binding:"required"` Type services.MessageType `json:"type"` ParentID *int64 `json:"parent_id,omitempty"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if req.Type == "" { req.Type = services.MessageTypeText } message, err := h.chatService.CreateMessage(c.Request.Context(), roomID, userID, req.Content, req.Type, req.ParentID) if err != nil { h.logger.Error("Failed to create message", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create message"}) return } c.JSON(http.StatusCreated, gin.H{ "success": true, "message": message, }) } // GetMessages retrieves messages for a room func (h *ChatHandlers) GetMessages(c *gin.Context) { roomID, err := strconv.ParseInt(c.Param("room_id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"}) return } page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) limit, _ := strconv.Atoi(c.DefaultQuery("limit", "50")) beforeIDStr := c.Query("before_id") var beforeID *int64 if beforeIDStr != "" { if id, err := strconv.ParseInt(beforeIDStr, 10, 64); err == nil { beforeID = &id } } messages, err := h.chatService.GetMessages(c.Request.Context(), roomID, page, limit, beforeID) if err != nil { h.logger.Error("Failed to get messages", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get messages"}) return } c.JSON(http.StatusOK, gin.H{ "success": true, "messages": messages, "page": page, "limit": limit, }) } // AddReaction adds a reaction to a message func (h *ChatHandlers) AddReaction(c *gin.Context) { userID := c.GetInt64("user_id") messageID, err := strconv.ParseInt(c.Param("message_id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid message ID"}) return } var req struct { Emoji string `json:"emoji" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } reaction, err := h.chatService.AddReaction(c.Request.Context(), messageID, userID, req.Emoji) if err != nil { h.logger.Error("Failed to add reaction", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to add reaction"}) return } c.JSON(http.StatusCreated, gin.H{ "success": true, "reaction": reaction, }) } // RemoveReaction removes a reaction from a message func (h *ChatHandlers) RemoveReaction(c *gin.Context) { userID := c.GetInt64("user_id") messageID, err := strconv.ParseInt(c.Param("message_id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid message ID"}) return } emoji := c.Param("emoji") if emoji == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "Emoji is required"}) return } err = h.chatService.RemoveReaction(c.Request.Context(), messageID, userID, emoji) if err != nil { h.logger.Error("Failed to remove reaction", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to remove reaction"}) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "Reaction removed", }) } // CreateRoom creates a new chat room func (h *ChatHandlers) CreateRoom(c *gin.Context) { userID := c.GetInt64("user_id") var req struct { Name string `json:"name" binding:"required"` Description string `json:"description"` Type services.RoomType `json:"type"` IsPrivate bool `json:"is_private"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } if req.Type == "" { req.Type = services.RoomTypePublic } room, err := h.chatService.CreateRoom(c.Request.Context(), req.Name, req.Description, req.Type, req.IsPrivate, userID) if err != nil { h.logger.Error("Failed to create room", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create room"}) return } c.JSON(http.StatusCreated, gin.H{ "success": true, "room": room, }) } // GetRooms retrieves available rooms func (h *ChatHandlers) GetRooms(c *gin.Context) { userID := c.GetInt64("user_id") includePrivate := c.DefaultQuery("include_private", "false") == "true" rooms, err := h.chatService.GetRooms(c.Request.Context(), userID, includePrivate) if err != nil { h.logger.Error("Failed to get rooms", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get rooms"}) return } c.JSON(http.StatusOK, gin.H{ "success": true, "rooms": rooms, }) } // JoinRoom adds a user to a room func (h *ChatHandlers) JoinRoom(c *gin.Context) { userID := c.GetInt64("user_id") roomID, err := strconv.ParseInt(c.Param("room_id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"}) return } err = h.chatService.JoinRoom(c.Request.Context(), roomID, userID) if err != nil { h.logger.Error("Failed to join room", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to join room"}) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "Successfully joined room", }) } // LeaveRoom removes a user from a room func (h *ChatHandlers) LeaveRoom(c *gin.Context) { userID := c.GetInt64("user_id") roomID, err := strconv.ParseInt(c.Param("room_id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"}) return } err = h.chatService.LeaveRoom(c.Request.Context(), roomID, userID) if err != nil { h.logger.Error("Failed to leave room", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to leave room"}) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "Successfully left room", }) } // CreateDirectMessage creates a DM room between two users func (h *ChatHandlers) CreateDirectMessage(c *gin.Context) { userID := c.GetInt64("user_id") var req struct { UserID int64 `json:"user_id" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } room, err := h.chatService.CreateDirectMessage(c.Request.Context(), userID, req.UserID) if err != nil { h.logger.Error("Failed to create DM", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create direct message"}) return } c.JSON(http.StatusCreated, gin.H{ "success": true, "room": room, }) } // SearchMessages searches for messages in a room func (h *ChatHandlers) SearchMessages(c *gin.Context) { roomID, err := strconv.ParseInt(c.Param("room_id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid room ID"}) return } query := c.Query("q") if query == "" { c.JSON(http.StatusBadRequest, gin.H{"error": "Search query is required"}) return } limit, _ := strconv.Atoi(c.DefaultQuery("limit", "20")) messages, err := h.chatService.SearchMessages(c.Request.Context(), roomID, query, limit) if err != nil { h.logger.Error("Failed to search messages", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to search messages"}) return } c.JSON(http.StatusOK, gin.H{ "success": true, "messages": messages, "query": query, "limit": limit, }) } // EditMessage edits an existing message func (h *ChatHandlers) EditMessage(c *gin.Context) { userID := c.GetInt64("user_id") messageID, err := strconv.ParseInt(c.Param("message_id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid message ID"}) return } var req struct { Content string `json:"content" binding:"required"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } message, err := h.chatService.EditMessage(c.Request.Context(), messageID, userID, req.Content) if err != nil { h.logger.Error("Failed to edit message", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to edit message"}) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": message, }) } // DeleteMessage deletes a message func (h *ChatHandlers) DeleteMessage(c *gin.Context) { userID := c.GetInt64("user_id") messageID, err := strconv.ParseInt(c.Param("message_id"), 10, 64) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid message ID"}) return } err = h.chatService.DeleteMessage(c.Request.Context(), messageID, userID) if err != nil { h.logger.Error("Failed to delete message", zap.Error(err)) c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete message"}) return } c.JSON(http.StatusOK, gin.H{ "success": true, "message": "Message deleted successfully", }) }