package com.lions.dev.service; import com.lions.dev.entity.chat.Conversation; import com.lions.dev.entity.chat.Message; import com.lions.dev.entity.users.Users; import com.lions.dev.exception.UserNotFoundException; import com.lions.dev.repository.ConversationRepository; import com.lions.dev.repository.MessageRepository; import com.lions.dev.repository.UsersRepository; import com.lions.dev.websocket.ChatWebSocket; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.transaction.Transactional; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; /** * Service de gestion des messages et conversations. * * Ce service contient la logique métier pour l'envoi de messages, * la récupération de conversations, et la gestion des messages non lus. * * Tous les logs nécessaires pour la traçabilité sont intégrés. */ @ApplicationScoped public class MessageService { @Inject MessageRepository messageRepository; @Inject ConversationRepository conversationRepository; @Inject UsersRepository usersRepository; @Inject NotificationService notificationService; /** * Envoie un message d'un utilisateur à un autre. * * @param senderId L'ID de l'expéditeur * @param recipientId L'ID du destinataire * @param content Le contenu du message * @param messageType Le type de message (text, image, etc.) * @param mediaUrl L'URL du média (optionnel) * @return Le message créé * @throws UserNotFoundException Si l'un des utilisateurs n'existe pas */ @Transactional public Message sendMessage( UUID senderId, UUID recipientId, String content, String messageType, String mediaUrl) { System.out.println("[LOG] Envoi de message de " + senderId + " à " + recipientId); // Récupérer les utilisateurs Users sender = usersRepository.findById(senderId); Users recipient = usersRepository.findById(recipientId); if (sender == null) { throw new UserNotFoundException("Expéditeur non trouvé avec l'ID : " + senderId); } if (recipient == null) { throw new UserNotFoundException("Destinataire non trouvé avec l'ID : " + recipientId); } // Trouver ou créer la conversation Conversation conversation = conversationRepository.findOrCreate(sender, recipient); // Créer le message Message message = new Message(conversation, sender, content); message.setMessageType(messageType != null ? messageType : "text"); if (mediaUrl != null && !mediaUrl.isEmpty()) { message.setMediaUrl(mediaUrl); } message.markAsDelivered(); // Persister le message messageRepository.persist(message); System.out.println("[LOG] Message créé avec l'ID : " + message.getId()); // Mettre à jour la conversation conversation.updateLastMessage(message); conversationRepository.persist(conversation); // Créer une notification pour le destinataire try { String senderName = sender.getPrenoms() + " " + sender.getNom(); String notificationMessage = content.length() > 50 ? content.substring(0, 50) + "..." : content; notificationService.createNotification( "Nouveau message de " + senderName, notificationMessage, "message", recipientId, null ); System.out.println("[LOG] Notification créée pour le destinataire"); } catch (Exception e) { System.out.println("[ERROR] Erreur lors de la création de la notification : " + e.getMessage()); } // TEMPS RÉEL : Envoyer le message via WebSocket au destinataire try { Map messageData = new HashMap<>(); messageData.put("id", message.getId().toString()); messageData.put("conversationId", conversation.getId().toString()); messageData.put("senderId", senderId.toString()); messageData.put("senderFirstName", sender.getPrenoms()); messageData.put("senderLastName", sender.getNom()); messageData.put("senderProfileImageUrl", sender.getProfileImageUrl() != null ? sender.getProfileImageUrl() : ""); messageData.put("content", content); messageData.put("timestamp", message.getCreatedAt().toString()); messageData.put("isRead", message.isRead()); messageData.put("attachmentUrl", mediaUrl != null ? mediaUrl : ""); messageData.put("attachmentType", messageType != null ? messageType : "text"); // Envoyer au destinataire via ChatWebSocket ChatWebSocket.sendMessageToUser(recipientId, messageData); System.out.println("[LOG] Message envoyé via WebSocket au destinataire : " + recipientId); // Envoyer confirmation de délivrance à l'expéditeur try { Map deliveryConfirmation = new HashMap<>(); deliveryConfirmation.put("messageId", message.getId().toString()); deliveryConfirmation.put("isDelivered", true); deliveryConfirmation.put("timestamp", System.currentTimeMillis()); ChatWebSocket.sendDeliveryConfirmation(senderId, deliveryConfirmation); System.out.println("[LOG] Confirmation de délivrance envoyée à l'expéditeur : " + senderId); } catch (Exception deliveryEx) { System.out.println("[ERROR] Erreur envoi confirmation délivrance : " + deliveryEx.getMessage()); // Ne pas bloquer si la confirmation échoue } } catch (Exception e) { System.out.println("[ERROR] Erreur lors de l'envoi du message via WebSocket : " + e.getMessage()); // Ne pas bloquer l'envoi du message si WebSocket échoue } return message; } /** * Récupère toutes les conversations d'un utilisateur. * * @param userId L'ID de l'utilisateur * @return Liste des conversations * @throws UserNotFoundException Si l'utilisateur n'existe pas */ public List getUserConversations(UUID userId) { System.out.println("[LOG] Récupération des conversations pour l'utilisateur ID : " + userId); Users user = usersRepository.findById(userId); if (user == null) { throw new UserNotFoundException("Utilisateur non trouvé avec l'ID : " + userId); } return conversationRepository.findByUser(user); } /** * Récupère tous les messages d'une conversation avec pagination. * * @param conversationId L'ID de la conversation * @param page Le numéro de la page * @param size La taille de la page * @return Liste paginée des messages */ public List getConversationMessages(UUID conversationId, int page, int size) { System.out.println("[LOG] Récupération des messages pour la conversation ID : " + conversationId); return messageRepository.findByConversationId(conversationId, page, size); } /** * Récupère une conversation spécifique. * * @param conversationId L'ID de la conversation * @return La conversation */ public Conversation getConversation(UUID conversationId) { System.out.println("[LOG] Récupération de la conversation ID : " + conversationId); return conversationRepository.findById(conversationId); } /** * Récupère une conversation entre deux utilisateurs. * * @param user1Id L'ID du premier utilisateur * @param user2Id L'ID du deuxième utilisateur * @return La conversation ou null si elle n'existe pas * @throws UserNotFoundException Si l'un des utilisateurs n'existe pas */ public Conversation getConversationBetweenUsers(UUID user1Id, UUID user2Id) { System.out.println("[LOG] Recherche de conversation entre " + user1Id + " et " + user2Id); Users user1 = usersRepository.findById(user1Id); Users user2 = usersRepository.findById(user2Id); if (user1 == null || user2 == null) { throw new UserNotFoundException("Un ou plusieurs utilisateurs non trouvés"); } return conversationRepository.findBetweenUsers(user1, user2); } /** * Marque un message comme lu. * * @param messageId L'ID du message * @return Le message mis à jour */ @Transactional public Message markMessageAsRead(UUID messageId) { System.out.println("[LOG] Marquage du message comme lu : " + messageId); Message message = messageRepository.findById(messageId); if (message == null) { throw new IllegalArgumentException("Message non trouvé avec l'ID : " + messageId); } message.markAsRead(); messageRepository.persist(message); // Envoyer confirmation de lecture à l'expéditeur via WebSocket try { // Récupérer le destinataire (l'autre utilisateur de la conversation) Conversation conversation = message.getConversation(); UUID recipientId = conversation.getUser1().getId().equals(message.getSender().getId()) ? conversation.getUser2().getId() : conversation.getUser1().getId(); Map readConfirmation = new HashMap<>(); readConfirmation.put("messageId", message.getId().toString()); readConfirmation.put("userId", recipientId.toString()); readConfirmation.put("timestamp", java.time.LocalDateTime.now().toString()); // Envoyer via ChatWebSocket avec type "read" com.lions.dev.websocket.ChatWebSocket.sendReadConfirmation( message.getSender().getId(), readConfirmation ); System.out.println("[LOG] Confirmation de lecture envoyée à l'expéditeur : " + message.getSender().getId()); } catch (Exception e) { System.out.println("[ERROR] Erreur envoi confirmation lecture : " + e.getMessage()); } return message; } /** * Marque tous les messages d'une conversation comme lus pour un utilisateur. * * @param conversationId L'ID de la conversation * @param userId L'ID de l'utilisateur * @return Le nombre de messages marqués comme lus */ @Transactional public int markAllMessagesAsRead(UUID conversationId, UUID userId) { System.out.println("[LOG] Marquage de tous les messages comme lus pour la conversation " + conversationId); Conversation conversation = conversationRepository.findById(conversationId); if (conversation == null) { throw new IllegalArgumentException("Conversation non trouvée"); } Users user = usersRepository.findById(userId); if (user == null) { throw new UserNotFoundException("Utilisateur non trouvé"); } // Marquer les messages comme lus int count = messageRepository.markAllAsRead(conversationId, userId); // Mettre à jour le compteur de la conversation conversation.markAllAsReadForUser(user); conversationRepository.persist(conversation); return count; } /** * Compte le nombre total de messages non lus pour un utilisateur. * * @param userId L'ID de l'utilisateur * @return Le nombre de messages non lus */ public long getTotalUnreadCount(UUID userId) { System.out.println("[LOG] Récupération du nombre total de messages non lus pour l'utilisateur " + userId); return conversationRepository.countTotalUnreadMessages(userId); } /** * Supprime un message. * * @param messageId L'ID du message * @return true si le message a été supprimé */ @Transactional public boolean deleteMessage(UUID messageId) { System.out.println("[LOG] Suppression du message ID : " + messageId); Message message = messageRepository.findById(messageId); if (message == null) { return false; } messageRepository.delete(message); return true; } /** * Supprime une conversation et tous ses messages. * * @param conversationId L'ID de la conversation * @return true si la conversation a été supprimée */ @Transactional public boolean deleteConversation(UUID conversationId) { System.out.println("[LOG] Suppression de la conversation ID : " + conversationId); // Supprimer d'abord tous les messages messageRepository.deleteByConversationId(conversationId); // Puis supprimer la conversation return conversationRepository.deleteConversation(conversationId); } }