using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Microsoft.EntityFrameworkCore; namespace Application.Features.Api.V1.Members.List; internal sealed class Handler(IAppDbContext db) : IQueryHandler { public async Task Handle(Query request, CancellationToken ct) { var page = Math.Max(1, request.Page); var size = Math.Clamp(request.Size, 1, 200); var baseQuery = db.Member .AsNoTracking() .Where(c => !c.IsWithdraw && c.DeletedAt == null); // hasChannel 필터: true → 채널 보유, false → 채널 미보유, null → 전체 if (request.HasChannel == true) { baseQuery = baseQuery.Where(c => c.Channel != null); } else if (request.HasChannel == false) { baseQuery = baseQuery.Where(c => c.Channel == null); } var total = await baseQuery.CountAsync(ct); var rows = await baseQuery .OrderByDescending(c => c.ID) .Skip((page - 1) * size) .Take(size) .Select(c => new { c.ID, c.SID, c.Name, c.Email, c.CreatedAt, ChannelSID = c.Channel != null ? c.Channel.SID : null, ChannelName = c.Channel != null ? c.Channel.Name : null }) .ToListAsync(ct); var items = rows.Select(r => new Response.Row( r.ID, r.SID, r.Name, MaskEmail(r.Email), r.ChannelSID != null, r.ChannelSID, r.ChannelName, r.CreatedAt )).ToList(); return new Response(total, page, size, items); } private static string MaskEmail(string email) { if (string.IsNullOrWhiteSpace(email)) { return string.Empty; } var atIndex = email.IndexOf('@'); if (atIndex <= 0) { return "***"; } var local = email[..atIndex]; var domain = email[(atIndex + 1)..]; var prefix = local.Length <= 2 ? local[..1] : local[..2]; return $"{prefix}***@{domain}"; } }