import { Request, Response } from 'express'; import Message from '../models/Message.js'; import OrganizationMember from '../models/OrganizationMember.js'; // Send a message export const sendMessage = async (req: Request, res: Response) => { try { const { toUserId, message } = req.body; const fromUserId = req.appUser?.externalId; const organizationId = req.headers['x-organization-id'] as string; if (!organizationId) { return res.status(400).json({ error: 'Organização não selecionada.' }); } if (!fromUserId) { return res.status(401).json({ error: 'Usuário não autenticado.' }); } if (!toUserId || !message) { return res.status(400).json({ error: 'Destinatário e mensagem são obrigatórios.' }); } if (message.length > 255) { return res.status(400).json({ error: 'Mensagem muito longa (máximo 255 caracteres).' }); } // Check if there's already a pending (unread) message from this user to that user const existingMessage = await Message.findOne({ organizationId, fromUserId, toUserId, isRead: false, }); if (existingMessage) { // Update existing message instead of creating a new one existingMessage.message = message; existingMessage.updatedAt = new Date(); await existingMessage.save(); return res.json(existingMessage); } // Create new message const newMessage = new Message({ organizationId, fromUserId, toUserId, message, }); await newMessage.save(); res.status(201).json(newMessage); } catch (error) { console.error('Error sending message:', error); res.status(500).json({ error: 'Erro ao enviar mensagem.' }); } }; // Get unread messages for current user export const getUnreadMessages = async (req: Request, res: Response) => { try { const toUserId = req.appUser?.externalId; const organizationId = req.headers['x-organization-id'] as string; if (!organizationId) { return res.status(400).json({ error: 'Organização não selecionada.' }); } if (!toUserId) { return res.status(401).json({ error: 'Usuário não autenticado.' }); } const messages = await Message.find({ organizationId, toUserId, isRead: false, isArchived: false, isDeletedByRecipient: false, }).sort({ createdAt: -1 }); // Populate sender info const messagesWithSender = await Promise.all( messages.map(async (msg) => { const sender = await OrganizationMember.findOne({ userId: msg.fromUserId }); return { ...msg.toObject(), fromUser: sender ? { name: sender.name, email: sender.email } : null, }; }) ); res.json(messagesWithSender); } catch (error) { console.error('Error getting unread messages:', error); res.status(500).json({ error: 'Erro ao buscar mensagens.' }); } }; // Mark message as read export const markMessageAsRead = async (req: Request, res: Response) => { try { const { id } = req.params; const userId = req.appUser?.externalId; const organizationId = req.headers['x-organization-id'] as string; if (!organizationId) { return res.status(400).json({ error: 'Organização não selecionada.' }); } if (!userId) { return res.status(401).json({ error: 'Usuário não autenticado.' }); } const message = await Message.findOne({ _id: id, organizationId, toUserId: userId, }); if (!message) { return res.status(404).json({ error: 'Mensagem não encontrada.' }); } message.isRead = true; message.readAt = new Date(); await message.save(); res.json(message); } catch (error) { console.error('Error marking message as read:', error); res.status(500).json({ error: 'Erro ao marcar mensagem como lida.' }); } }; // Get my pending (unread) sent messages export const getMyPendingMessages = async (req: Request, res: Response) => { try { const fromUserId = req.appUser?.externalId; const organizationId = req.headers['x-organization-id'] as string; if (!organizationId) { return res.status(400).json({ error: 'Organização não selecionada.' }); } if (!fromUserId) { return res.status(401).json({ error: 'Usuário não autenticado.' }); } const messages = await Message.find({ organizationId, fromUserId, isRead: false, }).sort({ createdAt: -1 }); // Populate recipient info const messagesWithRecipient = await Promise.all( messages.map(async (msg) => { const recipient = await OrganizationMember.findOne({ userId: msg.toUserId }); return { ...msg.toObject(), toUser: recipient ? { name: recipient.name, email: recipient.email } : null, }; }) ); res.json(messagesWithRecipient); } catch (error) { console.error('Error getting pending messages:', error); res.status(500).json({ error: 'Erro ao buscar mensagens pendentes.' }); } }; // Delete a message (only if unread and sender is the current user) export const deleteMessage = async (req: Request, res: Response) => { try { const { id } = req.params; const userId = req.appUser?.externalId; const organizationId = req.headers['x-organization-id'] as string; if (!organizationId) { return res.status(400).json({ error: 'Organização não selecionada.' }); } if (!userId) { return res.status(401).json({ error: 'Usuário não autenticado.' }); } const message = await Message.findOne({ _id: id, organizationId, fromUserId: userId, isRead: false, // Can only delete unread messages }); if (!message) { return res.status(404).json({ error: 'Mensagem não encontrada ou já foi lida.' }); } await message.deleteOne(); res.json({ message: 'Mensagem deletada com sucesso.' }); } catch (error) { console.error('Error deleting message:', error); res.status(500).json({ error: 'Erro ao deletar mensagem.' }); } }; // Recipient deletes/archives a message export const archiveMessage = async (req: Request, res: Response) => { try { const { id } = req.params; const userId = req.appUser?.externalId; const organizationId = req.headers['x-organization-id'] as string; const message = await Message.findOne({ _id: id, toUserId: userId, organizationId }); if (!message) return res.status(404).json({ error: 'Mensagem não encontrada.' }); message.isArchived = true; message.isRead = true; // Arquivar implica ler await message.save(); res.json(message); } catch (error) { console.error('Error archiving message:', error); res.status(500).json({ error: 'Erro ao arquivar mensagem.' }); } }; export const recipientDeleteMessage = async (req: Request, res: Response) => { try { const { id } = req.params; const userId = req.appUser?.externalId; const organizationId = req.headers['x-organization-id'] as string; const message = await Message.findOne({ _id: id, toUserId: userId, organizationId }); if (!message) return res.status(404).json({ error: 'Mensagem não encontrada.' }); message.isDeletedByRecipient = true; await message.save(); res.json({ message: 'Mensagem excluída com sucesso.' }); } catch (error) { console.error('Error deleting message:', error); res.status(500).json({ error: 'Erro ao excluir mensagem.' }); } };