using GozareshgirProgramManager.Application._Common.Interfaces; using GozareshgirProgramManager.Application._Common.Models; using GozareshgirProgramManager.Application.Modules.TaskChat.DTOs; using Microsoft.EntityFrameworkCore; namespace GozareshgirProgramManager.Application.Modules.TaskChat.Queries.GetMessages; public record GetMessagesQuery( Guid TaskId, int Page = 1, int PageSize = 50 ) : IBaseQuery>; public class GetMessagesQueryHandler : IBaseQueryHandler> { private readonly IProgramManagerDbContext _context; private readonly IAuthHelper _authHelper; public GetMessagesQueryHandler(IProgramManagerDbContext context, IAuthHelper authHelper) { _context = context; _authHelper = authHelper; } private List CreateAdditionalTimeNotes( IEnumerable additionalTimes, Dictionary users, Guid taskId) { var notes = new List(); foreach (var additionalTime in additionalTimes) { var addedByUserName = additionalTime.AddedByUserId.HasValue && users.TryGetValue(additionalTime.AddedByUserId.Value, out var user) ? user : "سیستم"; var noteContent = $"⏱️ زمان اضافی: {additionalTime.Hours.TotalHours.ToString("F2")} ساعت - {(string.IsNullOrWhiteSpace(additionalTime.Reason) ? "بدون علت" : additionalTime.Reason)} - توسط {addedByUserName}"; var noteDto = new MessageDto { Id = Guid.NewGuid(), TaskId = taskId, SenderUserId = 0, SenderName = "سیستم", MessageType = "Note", TextContent = noteContent, CreationDate = additionalTime.CreationDate, IsMine = false }; notes.Add(noteDto); } return notes; } public async Task>> Handle(GetMessagesQuery request, CancellationToken cancellationToken) { var currentUserId = _authHelper.GetCurrentUserId(); var skip = (request.Page - 1) * request.PageSize; var query = _context.TaskChatMessages .Where(m => m.TaskId == request.TaskId && !m.IsDeleted) .Include(m => m.ReplyToMessage) .OrderBy(m => m.CreationDate); var totalCount = await query.CountAsync(cancellationToken); var messages = await query .Skip(skip) .Take(request.PageSize) .ToListAsync(cancellationToken); // ✅ گرفتن تمامی کاربران برای نمایش نام کامل فرستنده به جای "کاربر" var senderUserIds = messages.Select(m => m.SenderUserId).Distinct().ToList(); var users = await _context.Users .Where(u => senderUserIds.Contains(u.Id)) .ToDictionaryAsync(u => u.Id, u => u.FullName, cancellationToken); // ✅ گرفتن تمامی زمان‌های اضافی (Additional Times) برای نمایش به صورت نوت var taskSections = await _context.TaskSections .Where(ts => ts.TaskId == request.TaskId) .Include(ts => ts.AdditionalTimes) .ToListAsync(cancellationToken); // ✅ تمام زمان‌های اضافی را یکجا بگیر و مرتب کن var allAdditionalTimes = taskSections .SelectMany(ts => ts.AdditionalTimes) .OrderBy(at => at.CreationDate) .ToList(); var messageDtos = new List(); // ✅ ابتدا زمان‌های اضافی قبل از اولین پیام را اضافه کن (اگر پیامی وجود داشته باشد) if (messages.Any()) { var firstMessageDate = messages.First().CreationDate; var additionalTimesBeforeFirstMessage = allAdditionalTimes .Where(at => at.CreationDate < firstMessageDate) .ToList(); messageDtos.AddRange(CreateAdditionalTimeNotes(additionalTimesBeforeFirstMessage, users, request.TaskId)); } else { // ✅ اگر هیچ پیامی وجود ندارد، همه زمان‌های اضافی را نمایش بده messageDtos.AddRange(CreateAdditionalTimeNotes(allAdditionalTimes, users, request.TaskId)); } foreach (var message in messages) { // ✅ نام فرستنده را از Dictionary Users بگیر، در صورت عدم وجود "کاربر ناشناس" نمایش بده var senderName = users.GetValueOrDefault(message.SenderUserId, "کاربر ناشناس"); var dto = new MessageDto { Id = message.Id, TaskId = message.TaskId, SenderUserId = message.SenderUserId, SenderName = senderName, MessageType = message.MessageType.ToString(), TextContent = message.TextContent, ReplyToMessageId = message.ReplyToMessageId, IsEdited = message.IsEdited, EditedDate = message.EditedDate, IsPinned = message.IsPinned, PinnedDate = message.PinnedDate, PinnedByUserId = message.PinnedByUserId, CreationDate = message.CreationDate, IsMine = message.SenderUserId == currentUserId }; if (message.ReplyToMessage != null) { var replySenderName = users.GetValueOrDefault(message.ReplyToMessage.SenderUserId, "کاربر ناشناس"); dto.ReplyToMessage = new MessageDto { Id = message.ReplyToMessage.Id, SenderUserId = message.ReplyToMessage.SenderUserId, SenderName = replySenderName, TextContent = message.ReplyToMessage.TextContent, CreationDate = message.ReplyToMessage.CreationDate }; } if (message.FileId.HasValue) { var file = await _context.UploadedFiles.FirstOrDefaultAsync(f => f.Id == message.FileId.Value, cancellationToken); if (file != null) { dto.File = new MessageFileDto { Id = file.Id, FileName = file.OriginalFileName, FileUrl = file.StorageUrl ?? "", FileSizeBytes = file.FileSizeBytes, FileType = file.FileType.ToString(), ThumbnailUrl = file.ThumbnailUrl, ImageWidth = file.ImageWidth, ImageHeight = file.ImageHeight, DurationSeconds = file.DurationSeconds }; } } messageDtos.Add(dto); // ✅ پیدا کردن پیام بعدی (اگر وجود داشته باشد) var currentIndex = messages.IndexOf(message); var nextMessage = currentIndex < messages.Count - 1 ? messages[currentIndex + 1] : null; if (nextMessage != null) { // ✅ زمان‌های اضافی بین این پیام و پیام بعدی var additionalTimesBetween = allAdditionalTimes .Where(at => at.CreationDate > message.CreationDate && at.CreationDate < nextMessage.CreationDate) .ToList(); messageDtos.AddRange(CreateAdditionalTimeNotes(additionalTimesBetween, users, request.TaskId)); } else { // ✅ این آخرین پیام است، زمان‌های اضافی بعد از آن را اضافه کن var additionalTimesAfterLastMessage = allAdditionalTimes .Where(at => at.CreationDate > message.CreationDate) .ToList(); messageDtos.AddRange(CreateAdditionalTimeNotes(additionalTimesAfterLastMessage, users, request.TaskId)); } } // ✅ مرتب کردن نهایی تمام پیام‌ها (معمولی + نوت‌ها) بر اساس زمان ایجاد messageDtos = messageDtos.OrderBy(m => m.CreationDate).ToList(); var response = new PaginationResult() { List = messageDtos, TotalCount = totalCount, }; return OperationResult>.Success(response); } }