import { ForbiddenException, forwardRef, Inject, Injectable, } from "@nestjs/common"; import { EventsGateway } from "../realtime/events.gateway"; import { UsersService } from "../users/users.service"; import type { CreateMessageDto } from "./dto/create-message.dto"; import { MessagesRepository } from "./repositories/messages.repository"; @Injectable() export class MessagesService { constructor( private readonly messagesRepository: MessagesRepository, private readonly eventsGateway: EventsGateway, @Inject(forwardRef(() => UsersService)) private readonly usersService: UsersService, ) {} async sendMessage(senderId: string, dto: CreateMessageDto) { let conversation = await this.messagesRepository.findConversationBetweenUsers( senderId, dto.recipientId, ); if (!conversation) { const newConv = await this.messagesRepository.createConversation(); await this.messagesRepository.addParticipant(newConv.id, senderId); await this.messagesRepository.addParticipant(newConv.id, dto.recipientId); conversation = newConv; } const message = await this.messagesRepository.createMessage({ conversationId: conversation.id, senderId, text: dto.text, }); // Notify recipient via WebSocket this.eventsGateway.sendToUser(dto.recipientId, "new_message", { conversationId: conversation.id, message, }); return message; } async getConversations(userId: string) { return this.messagesRepository.findAllConversations(userId); } async getUnreadCount(userId: string) { return this.messagesRepository.countUnreadMessages(userId); } async getConversationWithUser(userId: string, targetUserId: string) { return this.messagesRepository.findConversationBetweenUsers( userId, targetUserId, ); } async getMessages(userId: string, conversationId: string) { const isParticipant = await this.messagesRepository.isParticipant( conversationId, userId, ); if (!isParticipant) { throw new ForbiddenException("You are not part of this conversation"); } // Récupérer les préférences de l'utilisateur actuel const user = await this.usersService.findOne(userId); // Marquer comme lus seulement si l'utilisateur l'autorise if (user?.showReadReceipts) { await this.messagesRepository.markAsRead(conversationId, userId); // Notifier l'expéditeur que les messages ont été lus const participants = await this.messagesRepository.getParticipants(conversationId); const otherParticipant = participants.find((p) => p.userId !== userId); if (otherParticipant) { this.eventsGateway.sendToUser(otherParticipant.userId, "messages_read", { conversationId, readerId: userId, }); } } return this.messagesRepository.findMessagesByConversationId(conversationId); } async markAsRead(userId: string, conversationId: string) { const isParticipant = await this.messagesRepository.isParticipant( conversationId, userId, ); if (!isParticipant) { throw new ForbiddenException("You are not part of this conversation"); } const user = await this.usersService.findOne(userId); if (!user?.showReadReceipts) return; const result = await this.messagesRepository.markAsRead( conversationId, userId, ); // Notifier l'autre participant const participants = await this.messagesRepository.getParticipants(conversationId); const otherParticipant = participants.find((p) => p.userId !== userId); if (otherParticipant) { this.eventsGateway.sendToUser(otherParticipant.userId, "messages_read", { conversationId, readerId: userId, }); } return result; } }