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() ?? [];
}
}
}