package dev.lions.unionflow.server.service; import dev.lions.unionflow.server.api.dto.communication.request.SendMessageRequest; import dev.lions.unionflow.server.api.dto.communication.response.MessageResponse; import dev.lions.unionflow.server.api.enums.communication.MessagePriority; import dev.lions.unionflow.server.api.enums.communication.MessageStatus; import dev.lions.unionflow.server.api.enums.communication.MessageType; import dev.lions.unionflow.server.entity.Conversation; import dev.lions.unionflow.server.entity.Membre; import dev.lions.unionflow.server.entity.Message; import dev.lions.unionflow.server.repository.ConversationRepository; import dev.lions.unionflow.server.repository.MembreRepository; import dev.lions.unionflow.server.repository.MessageRepository; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.transaction.Transactional; import jakarta.ws.rs.NotFoundException; import org.jboss.logging.Logger; import java.time.LocalDateTime; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; /** * Service de gestion des messages * * @author UnionFlow Team * @version 1.0 * @since 2026-03-16 */ @ApplicationScoped public class MessageService { private static final Logger LOG = Logger.getLogger(MessageService.class); @Inject MessageRepository messageRepository; @Inject ConversationRepository conversationRepository; @Inject MembreRepository membreRepository; /** * Récupère les messages d'une conversation */ public List getMessages(UUID conversationId, UUID membreId, int limit) { LOG.infof("Récupération messages pour conversation %s (limit: %d)", conversationId, limit); // Vérifier accès conversationRepository.findByIdAndParticipant(conversationId, membreId) .orElseThrow(() -> new NotFoundException("Conversation non trouvée ou accès refusé")); List messages = messageRepository.findByConversation(conversationId, limit); return messages.stream() .map(this::convertToResponse) .collect(Collectors.toList()); } /** * Envoie un message */ @Transactional public MessageResponse sendMessage(SendMessageRequest request, UUID senderId) { LOG.infof("Envoi message dans conversation %s", request.conversationId()); // Vérifier accès conversation Conversation conversation = conversationRepository.findByIdAndParticipant(request.conversationId(), senderId) .orElseThrow(() -> new NotFoundException("Conversation non trouvée ou accès refusé")); Membre sender = membreRepository.findById(senderId); if (sender == null) { throw new NotFoundException("Expéditeur non trouvé"); } Message message = new Message(); message.setConversation(conversation); message.setSender(sender); message.setSenderName(sender.getPrenom() + " " + sender.getNom()); message.setSenderAvatar(sender.getPhotoUrl()); message.setContent(request.content()); message.setType(request.type() != null ? request.type() : MessageType.INDIVIDUAL); message.setStatus(MessageStatus.SENT); message.setPriority(request.priority() != null ? request.priority() : MessagePriority.NORMAL); // Destinataires (pour targeted messages) if (request.recipientIds() != null && !request.recipientIds().isEmpty()) { message.setRecipientIds(request.recipientIds().stream() .map(UUID::toString) .collect(Collectors.joining(","))); } // Rôles destinataires if (request.recipientRoles() != null && !request.recipientRoles().isEmpty()) { message.setRecipientRoles(String.join(",", request.recipientRoles())); } // Pièces jointes if (request.attachments() != null && !request.attachments().isEmpty()) { message.setAttachments(String.join(",", request.attachments())); } message.setOrganisation(conversation.getOrganisation()); messageRepository.persist(message); // Mettre à jour la conversation conversation.setUpdatedAt(LocalDateTime.now()); conversationRepository.persist(conversation); LOG.infof("Message %s créé avec succès", message.getId()); return convertToResponse(message); } /** * Édite un message */ @Transactional public MessageResponse editMessage(UUID messageId, UUID senderId, String newContent) { Message message = messageRepository.findById(messageId); if (message == null) { throw new NotFoundException("Message non trouvé"); } if (!message.getSender().getId().equals(senderId)) { throw new IllegalStateException("Vous ne pouvez éditer que vos propres messages"); } message.setContent(newContent); message.markAsEdited(); messageRepository.persist(message); return convertToResponse(message); } /** * Supprime un message (soft delete) */ @Transactional public void deleteMessage(UUID messageId, UUID senderId) { Message message = messageRepository.findById(messageId); if (message == null) { throw new NotFoundException("Message non trouvé"); } if (!message.getSender().getId().equals(senderId)) { throw new IllegalStateException("Vous ne pouvez supprimer que vos propres messages"); } message.setIsDeleted(true); message.setContent("[Message supprimé]"); messageRepository.persist(message); } /** * Convertit Message en DTO */ private MessageResponse convertToResponse(Message m) { // Parser recipient IDs List recipientIds = null; if (m.getRecipientIds() != null && !m.getRecipientIds().isEmpty()) { recipientIds = List.of(m.getRecipientIds().split(",")).stream() .map(UUID::fromString) .collect(Collectors.toList()); } // Parser roles List roles = null; if (m.getRecipientRoles() != null && !m.getRecipientRoles().isEmpty()) { roles = List.of(m.getRecipientRoles().split(",")); } // Parser attachments List attachments = null; if (m.getAttachments() != null && !m.getAttachments().isEmpty()) { attachments = List.of(m.getAttachments().split(",")); } return MessageResponse.builder() .id(m.getId()) .conversationId(m.getConversation().getId()) .senderId(m.getSender().getId()) .senderName(m.getSenderName()) .senderAvatar(m.getSenderAvatar()) .content(m.getContent()) .type(m.getType()) .status(m.getStatus()) .priority(m.getPriority()) .recipientIds(recipientIds) .recipientRoles(roles) .organisationId(m.getOrganisation() != null ? m.getOrganisation().getId() : null) .createdAt(m.getDateCreation()) .readAt(m.getReadAt()) .attachments(attachments) .isEdited(m.getIsEdited()) .editedAt(m.getEditedAt()) .isDeleted(m.getIsDeleted()) .build(); } }