using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Microsoft.EntityFrameworkCore; namespace Application.Features.Api.Feed.GetSuggestedFollows; public sealed class Handler(IAppDbContext db) : IQueryHandler { public async Task Handle(Query request, CancellationToken ct) { var top = Math.Clamp(request.Top, 1, 20); var viewerID = request.ViewerMemberID ?? 0; var followingIDs = viewerID > 0 ? await db.MemberFollow.AsNoTracking().Where(f => f.FollowerMemberID == viewerID).Select(f => f.FolloweeMemberID).ToListAsync(ct) : []; var query = db.Member.AsNoTracking() .Where(m => m.IsCreator && !m.IsWithdraw && !m.IsDenied && m.ID != viewerID && !followingIDs.Contains(m.ID)) .Select(m => new { m.SID, m.Name, m.Thumb, m.Summary, m.IsCreator, FollowerCount = m.MemberStats != null ? m.MemberStats.FollowerCount : 0 }); var list = await query.OrderByDescending(x => x.FollowerCount).Take(top).ToListAsync(ct); if (list.Count < top) { var fallbackTake = top - list.Count; var existingSIDs = list.Select(x => x.SID).ToList(); var fallback = await db.Member.AsNoTracking() .Where(m => !m.IsWithdraw && !m.IsDenied && m.ID != viewerID && !followingIDs.Contains(m.ID) && !existingSIDs.Contains(m.SID)) .Select(m => new { m.SID, m.Name, m.Thumb, m.Summary, m.IsCreator, FollowerCount = m.MemberStats != null ? m.MemberStats.FollowerCount : 0 }) .OrderByDescending(x => x.FollowerCount) .Take(fallbackTake) .ToListAsync(ct); list.AddRange(fallback); } return new Response { List = [..list.Select(x => new Response.Row { SID = x.SID, Name = x.Name, Thumb = x.Thumb, Summary = x.Summary, IsCreator = x.IsCreator, FollowerCount = x.FollowerCount })] }; } }