using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Domain.Entities.Donations.ValueObject; using Microsoft.EntityFrameworkCore; namespace Application.Features.Api.Crew.GetActiveCrewForChannel; internal sealed class Handler(IAppDbContext db) : IQueryHandler { public async Task Handle(Query request, CancellationToken ct) { var channel = await db.Channel.AsNoTracking() .FirstOrDefaultAsync(c => c.SID == request.ChannelSID, ct); if (channel is null) return null; // 채널에 연결된 크루 중 Active 세션이 있는지 확인 var session = await db.CrewSession.AsNoTracking() .Where(s => s.Status == CrewSessionStatus.Active) .Join(db.Crew.Where(c => c.ChannelID == channel.ID), s => s.CrewID, c => c.ID, (s, c) => new { Session = s, Crew = c }) .FirstOrDefaultAsync(ct); if (session is null) return null; var members = await db.CrewDonationSummary.AsNoTracking() .Where(s => s.CrewSessionID == session.Session.ID) .Join(db.CrewMember, s => s.CrewMemberID, m => m.ID, (s, m) => new { Summary = s, Member = m }) .OrderBy(x => x.Summary.Rank) .Select(x => new CrewMemberInfo( x.Member.ID, x.Member.Nickname, x.Member.Member != null ? x.Member.Member.Thumb : null, x.Member.Channel != null ? x.Member.Channel.Name : null )) .ToListAsync(ct); return new Response( session.Session.ID, session.Session.Title, session.Crew.Name, members ); } }