using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Knot.Modules.Relations.Domain; using Knot.Shared.Kernel; using Microsoft.EntityFrameworkCore; using Knot.Modules.Relations.Application.Abstractions; namespace Knot.Modules.Relations.Application.Contacts; public record ContactUserDto(Guid Id, string Username, string DisplayName, string Avatar); public record ContactRequestDto(Guid Id, ContactUserDto User, DateTime CreatedAt, bool IsOutgoing); public record GetContactRequestsQuery(Guid UserId) : IQuery>; internal sealed class GetContactRequestsQueryHandler : IQueryHandler> { private readonly IContactsDbContext _context; public GetContactRequestsQueryHandler(IContactsDbContext context) { _context = context; } public async Task>> Handle(GetContactRequestsQuery request, CancellationToken cancellationToken) { // 1. Fetch ALL pending requests where current user is either sender or receiver var contacts = await _context.Contacts .Where(c => (c.ContactId == request.UserId || c.UserId == request.UserId) && c.Status == ContactStatus.Pending) .ToListAsync(cancellationToken); // 2. Fetch all unique IDs for users we need replicas for var userIds = contacts .Select(c => c.UserId == request.UserId ? c.ContactId : c.UserId) .Distinct() .ToList(); // 3. Fetch replicas var replicas = await _context.UserReplicas .Where(r => userIds.Contains(r.Id)) .ToDictionaryAsync(r => r.Id, cancellationToken); // 4. Transform into DTOs var result = contacts .Select(c => { var isOutgoing = c.UserId == request.UserId; var otherUserId = isOutgoing ? c.ContactId : c.UserId; // If replica is missing, we try to at least return the record (Visibility fix part 1) // We will handle replica creation in SendContactRequest proactively. if (!replicas.TryGetValue(otherUserId, out var user)) { return new ContactRequestDto( c.Id, new ContactUserDto(otherUserId, "Unknown", "Unknown", ""), c.CreatedAt, isOutgoing ); } return new ContactRequestDto( c.Id, new ContactUserDto(user.Id, user.Username, user.DisplayName, user.Avatar), c.CreatedAt, isOutgoing ); }) .ToList(); return Result.Success(result); } }