using Nuuru.Server.DTOs.Messaging; using Nuuru.Server.Models.Messaging; using Nuuru.Server.Services; namespace Nuuru.Server.Extensions { /// /// Extension methods for mapping between Messaging entities and DTOs /// public static class MessagingMappingExtensions { /// /// Maps a Conversation entity to ConversationDto /// /// The conversation to map /// The user requesting the conversation /// Optional display info map for badge/color lookup public static ConversationDto ToDto( this Conversation conversation, Guid requestingUserId, Dictionary? displayInfoMap = null) { if (conversation == null) return null!; UserDisplayInfo? creatorDisplayInfo = null; if (conversation.Creator != null && displayInfoMap != null) { displayInfoMap.TryGetValue(conversation.Creator.Id, out creatorDisplayInfo); } // Calculate unread status var userParticipant = conversation.Participants?.FirstOrDefault(p => p.UserId == requestingUserId); var hasUnread = userParticipant != null && (userParticipant.LastReadAt == null || conversation.LastMessageAt > userParticipant.LastReadAt); // Generate display title var displayTitle = GenerateDisplayTitle(conversation, requestingUserId); // Get last message var lastMessage = conversation.Messages?.OrderByDescending(m => m.CreatedAt).FirstOrDefault(); return new ConversationDto { Id = conversation.Id, Title = conversation.Title, DisplayTitle = displayTitle, CreatedAt = conversation.CreatedAt, LastMessageAt = conversation.LastMessageAt, MessageCount = conversation.MessageCount, IsLocked = conversation.IsLocked, HasUnread = hasUnread, UnreadCount = hasUnread ? 1 : 0, // Simplified - just indicate unread Creator = conversation.Creator?.ToUploaderDto(creatorDisplayInfo)!, Participants = conversation.Participants? .Select(p => p.ToDto(displayInfoMap)) .ToList() ?? [], LastMessage = lastMessage?.ToDto(requestingUserId, displayInfoMap) }; } /// /// Generates a display title for a conversation if no explicit title is set /// private static string GenerateDisplayTitle(Conversation conversation, Guid requestingUserId) { if (!string.IsNullOrWhiteSpace(conversation.Title)) { return conversation.Title; } // For conversations without a title, generate from participant names var otherParticipants = conversation.Participants? .Where(p => p.UserId != requestingUserId && !p.HasLeft) .Select(p => p.User?.UserName ?? "Unknown") .Take(3) .ToList() ?? []; if (otherParticipants.Count == 0) { return "Conversation"; } if (otherParticipants.Count == 1) { return otherParticipants[0]; } if (otherParticipants.Count == 2) { return $"{otherParticipants[0]} and {otherParticipants[1]}"; } var remaining = (conversation.Participants?.Count(p => p.UserId != requestingUserId && !p.HasLeft) ?? 0) - 2; return $"{otherParticipants[0]}, {otherParticipants[1]} and {remaining} others"; } /// /// Maps a ConversationParticipant entity to ConversationParticipantDto /// public static ConversationParticipantDto ToDto( this ConversationParticipant participant, Dictionary? displayInfoMap = null) { if (participant == null) return null!; UserDisplayInfo? userDisplayInfo = null; if (participant.User != null && displayInfoMap != null) { displayInfoMap.TryGetValue(participant.User.Id, out userDisplayInfo); } return new ConversationParticipantDto { UserId = participant.UserId, User = participant.User?.ToUploaderDto(userDisplayInfo)!, JoinedAt = participant.JoinedAt, HasLeft = participant.HasLeft }; } /// /// Maps a collection of Conversations to ConversationDtos /// public static List ToDto( this IEnumerable conversations, Guid requestingUserId, Dictionary? displayInfoMap = null) { return conversations?.Select(c => c.ToDto(requestingUserId, displayInfoMap)).ToList() ?? []; } /// /// Maps a Message entity to MessageDto /// /// The message to map /// If provided, includes raw content only if this user is the author /// Optional display info map for badge/color lookup public static MessageDto ToDto( this Message message, Guid? requestingUserId = null, Dictionary? displayInfoMap = null) { if (message == null) return null!; UserDisplayInfo? authorDisplayInfo = null; if (message.Author != null && displayInfoMap != null) { displayInfoMap.TryGetValue(message.Author.Id, out authorDisplayInfo); } return new MessageDto { Id = message.Id, ContentHtml = message.ContentHtml, // Include raw content for all conversation participants (needed for quoting) ContentRaw = message.ContentRaw, CreatedAt = message.CreatedAt, EditedAt = message.EditedAt, Author = message.Author?.ToUploaderDto(authorDisplayInfo)!, ConversationId = message.ConversationId }; } /// /// Maps a collection of Messages to MessageDtos /// public static List ToDto( this IEnumerable messages, Guid? requestingUserId = null, Dictionary? displayInfoMap = null) { return messages?.Select(m => m.ToDto(requestingUserId, displayInfoMap)).ToList() ?? []; } } }