package chat import ( "context" "encoding/json" "time" "veza-backend-api/internal/models" "github.com/google/uuid" "go.uber.org/zap" ) func (h *MessageHandler) HandleSendMessage(ctx context.Context, client *Client, msg *IncomingMessage) { if msg.ConversationID == nil { client.SendJSON(NewErrorResponse("conversation_id is required")) return } if msg.Content == "" { client.SendJSON(NewErrorResponse("content is required")) return } if !h.rateLimiter.Allow(client.UserID, "send_message") { client.SendJSON(NewErrorResponse("rate limit exceeded")) return } if !h.permissions.CanSend(ctx, client.UserID, *msg.ConversationID) { client.SendJSON(NewErrorResponse("not allowed to send messages in this conversation")) return } var metadata []byte if len(msg.Attachments) > 0 { metadata, _ = json.Marshal(map[string]interface{}{ "attachments": msg.Attachments, }) } chatMsg := &models.ChatMessage{ ID: uuid.New(), ConversationID: *msg.ConversationID, SenderID: client.UserID, Content: msg.Content, MessageType: "text", ParentMessageID: msg.ParentMessageID, Status: "sent", Metadata: metadata, CreatedAt: time.Now(), UpdatedAt: time.Now(), } if err := h.msgRepo.Create(ctx, chatMsg); err != nil { h.logger.Error("Failed to save message", zap.Error(err), zap.String("user_id", client.UserID.String())) client.SendJSON(NewErrorResponse("failed to send message")) return } client.SendJSON(NewActionConfirmedResponse("message_sent", true)) outgoing := NewNewMessageResponse( chatMsg.ConversationID, chatMsg.ID, chatMsg.SenderID, chatMsg.Content, chatMsg.CreatedAt, msg.Attachments, ) 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) HandleEditMessage(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.NewContent == "" { client.SendJSON(NewErrorResponse("new_content is required")) return } chatMsg, err := h.msgRepo.GetByID(ctx, *msg.MessageID) if err != nil { client.SendJSON(NewErrorResponse("message not found")) return } if chatMsg.SenderID != client.UserID { client.SendJSON(NewErrorResponse("can only edit your own messages")) return } now := time.Now() chatMsg.Content = msg.NewContent chatMsg.IsEdited = true chatMsg.EditedAt = &now if err := h.msgRepo.Update(ctx, chatMsg); err != nil { h.logger.Error("Failed to update message", zap.Error(err)) client.SendJSON(NewErrorResponse("failed to edit message")) return } client.SendJSON(NewActionConfirmedResponse("message_edited", true)) outgoing := NewMessageEditedResponse( chatMsg.ID, chatMsg.ConversationID, client.UserID, now, msg.NewContent, ) 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) HandleDeleteMessage(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 } chatMsg, err := h.msgRepo.GetByID(ctx, *msg.MessageID) if err != nil { client.SendJSON(NewErrorResponse("message not found")) return } isModerator := h.permissions.CanModerate(ctx, client.UserID, *msg.ConversationID) if chatMsg.SenderID != client.UserID && !isModerator { client.SendJSON(NewErrorResponse("can only delete your own messages")) return } if err := h.msgRepo.SoftDelete(ctx, *msg.MessageID); err != nil { h.logger.Error("Failed to delete message", zap.Error(err)) client.SendJSON(NewErrorResponse("failed to delete message")) return } client.SendJSON(NewActionConfirmedResponse("message_deleted", true)) outgoing := NewMessageDeletedResponse( *msg.MessageID, *msg.ConversationID, client.UserID, time.Now(), ) data, _ := json.Marshal(outgoing) h.hub.BroadcastToRoom(*msg.ConversationID, data, nil) if h.pubsub != nil { _ = h.pubsub.Publish(ctx, *msg.ConversationID, data) } }