using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Microsoft.EntityFrameworkCore; using SharedKernel.Results; namespace Application.Features.Api.Member.Profile; public sealed class Handler(IAppDbContext db) : IQueryHandler> { private const string FeedBoardCode = "feed"; public async Task> Handle(Query request, CancellationToken ct) { var member = await db.Member.AsNoTracking() .Where(m => m.SID == request.MemberSID && !m.IsWithdraw && !m.IsDenied) .Select(m => new { m.ID, m.SID, m.Name, m.Thumb, m.BannerUrl, m.Summary, m.Intro, m.IsCreator, m.IsAdmin, m.IsAuthCertified, JoinedAt = m.CreatedAt, m.LastLoginAt, ChannelSID = m.Channel != null ? m.Channel.SID : null, ChannelHandle = m.Channel != null ? m.Channel.Handle : null, Stats = m.MemberStats == null ? null : new { m.MemberStats.FollowerCount, m.MemberStats.FollowingCount, m.MemberStats.PostCount, m.MemberStats.CommentCount, m.MemberStats.AttendanceCount, m.MemberStats.Exp, m.MemberStats.LikeReceivedCount } }) .FirstOrDefaultAsync(ct); if (member is null) { return Result.Failure(Error.NotFound("Member.ProfileNotFound", "회원을 찾을 수 없습니다.")); } var feedBoardID = await db.Board.AsNoTracking().Where(b => b.Code == FeedBoardCode).Select(b => (int?)b.ID).FirstOrDefaultAsync(ct); var feedPostCount = feedBoardID is int fid ? await db.Post.AsNoTracking().LongCountAsync(p => p.BoardID == fid && p.MemberID == member.ID && !p.IsDeleted, ct) : 0; var consecutiveDays = await db.Attendance.AsNoTracking() .Where(a => a.MemberID == member.ID) .OrderByDescending(a => a.CreatedAt) .Select(a => (int?)a.ConsecutiveDays) .FirstOrDefaultAsync(ct) ?? 0; var viewerID = request.ViewerMemberID ?? 0; var isSelf = viewerID > 0 && viewerID == member.ID; var isFollowing = false; if (viewerID > 0 && !isSelf) { isFollowing = await db.MemberFollow.AsNoTracking().AnyAsync(f => f.FollowerMemberID == viewerID && f.FolloweeMemberID == member.ID, ct); } return new Response { MemberID = member.ID, MemberSID = member.SID, Name = member.Name, Thumb = member.Thumb, BannerUrl = member.BannerUrl, Summary = member.Summary, Intro = member.Intro, IsCreator = member.IsCreator, IsAdmin = member.IsAdmin, IsAuthCertified = member.IsAuthCertified, JoinedAt = member.JoinedAt, LastLoginAt = member.LastLoginAt, ChannelSID = member.ChannelSID, ChannelHandle = member.ChannelHandle, FollowerCount = member.Stats?.FollowerCount ?? 0, FollowingCount = member.Stats?.FollowingCount ?? 0, PostCount = member.Stats?.PostCount ?? 0, CommentCount = member.Stats?.CommentCount ?? 0, FeedPostCount = feedPostCount, AttendanceCount = member.Stats?.AttendanceCount ?? 0, ConsecutiveDays = consecutiveDays, Exp = member.Stats?.Exp ?? 0, LikeReceivedCount = member.Stats?.LikeReceivedCount ?? 0, IsFollowing = isFollowing, IsSelf = isSelf }; } }