package chat import ( "context" "encoding/json" "time" "veza-backend-api/internal/models" "github.com/google/uuid" "go.uber.org/zap" ) func (h *MessageHandler) HandleTyping(ctx context.Context, client *Client, msg *IncomingMessage) { if msg.ConversationID == nil { client.SendJSON(NewErrorResponse("conversation_id is required")) return } if !h.rateLimiter.Allow(client.UserID, "typing") { return } isTyping := true if msg.IsTyping != nil { isTyping = *msg.IsTyping } outgoing := NewUserTypingResponse(*msg.ConversationID, client.UserID, isTyping) data, _ := json.Marshal(outgoing) h.hub.BroadcastToRoom(*msg.ConversationID, data, client) client.SendJSON(NewActionConfirmedResponse("typing_indicator", true)) } func (h *MessageHandler) HandleMarkAsRead(ctx context.Context, client *Client, msg *IncomingMessage) { if msg.ConversationID == nil || msg.MessageID == nil { client.SendJSON(NewErrorResponse("conversation_id and message_id are required")) return } receipt := &models.ReadReceipt{ ID: uuid.New(), UserID: client.UserID, MessageID: *msg.MessageID, ReadAt: time.Now(), } if err := h.readRepo.MarkRead(ctx, receipt); err != nil { h.logger.Error("Failed to mark as read", zap.Error(err)) client.SendJSON(NewErrorResponse("failed to mark as read")) return } client.SendJSON(NewActionConfirmedResponse("marked_as_read", true)) outgoing := NewMessageReadResponse(*msg.MessageID, client.UserID, *msg.ConversationID, receipt.ReadAt) data, _ := json.Marshal(outgoing) h.hub.BroadcastToRoom(*msg.ConversationID, data, client) if h.pubsub != nil { _ = h.pubsub.Publish(ctx, *msg.ConversationID, data) } } func (h *MessageHandler) HandleDelivered(ctx context.Context, client *Client, msg *IncomingMessage) { if msg.ConversationID == nil || msg.MessageID == nil { client.SendJSON(NewErrorResponse("conversation_id and message_id are required")) return } status := &models.DeliveredStatus{ ID: uuid.New(), UserID: client.UserID, MessageID: *msg.MessageID, DeliveredAt: time.Now(), } if err := h.deliveredRepo.MarkDelivered(ctx, status); err != nil { h.logger.Error("Failed to mark as delivered", zap.Error(err)) client.SendJSON(NewErrorResponse("failed to mark as delivered")) return } client.SendJSON(NewActionConfirmedResponse("marked_as_delivered", true)) outgoing := NewMessageDeliveredResponse(*msg.MessageID, client.UserID, *msg.ConversationID, status.DeliveredAt) data, _ := json.Marshal(outgoing) h.hub.BroadcastToRoom(*msg.ConversationID, data, client) if h.pubsub != nil { _ = h.pubsub.Publish(ctx, *msg.ConversationID, data) } } func (h *MessageHandler) HandleAddReaction(ctx context.Context, client *Client, msg *IncomingMessage) { if msg.MessageID == nil || msg.ConversationID == nil { client.SendJSON(NewErrorResponse("message_id and conversation_id are required")) return } if msg.Emoji == "" { client.SendJSON(NewErrorResponse("emoji is required")) return } reaction := &models.MessageReaction{ ID: uuid.New(), UserID: client.UserID, MessageID: *msg.MessageID, Emoji: msg.Emoji, CreatedAt: time.Now(), } if err := h.reactionRepo.Add(ctx, reaction); err != nil { h.logger.Error("Failed to add reaction", zap.Error(err)) client.SendJSON(NewErrorResponse("failed to add reaction")) return } client.SendJSON(NewActionConfirmedResponse("reaction_added", true)) outgoing := NewReactionAddedResponse(*msg.MessageID, *msg.ConversationID, client.UserID, msg.Emoji) data, _ := json.Marshal(outgoing) h.hub.BroadcastToRoom(*msg.ConversationID, data, nil) if h.pubsub != nil { _ = h.pubsub.Publish(ctx, *msg.ConversationID, data) } } func (h *MessageHandler) HandleRemoveReaction(ctx context.Context, client *Client, msg *IncomingMessage) { if msg.MessageID == nil || msg.ConversationID == nil { client.SendJSON(NewErrorResponse("message_id and conversation_id are required")) return } if err := h.reactionRepo.Remove(ctx, client.UserID, *msg.MessageID); err != nil { h.logger.Error("Failed to remove reaction", zap.Error(err)) client.SendJSON(NewErrorResponse("failed to remove reaction")) return } client.SendJSON(NewActionConfirmedResponse("reaction_removed", true)) outgoing := NewReactionRemovedResponse(*msg.MessageID, *msg.ConversationID, client.UserID) data, _ := json.Marshal(outgoing) h.hub.BroadcastToRoom(*msg.ConversationID, data, nil) if h.pubsub != nil { _ = h.pubsub.Publish(ctx, *msg.ConversationID, data) } }