using Application.Abstractions.Data; using Application.Abstractions.Messaging; using Application.Abstractions.YouTube; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; using SharedKernel; namespace Application.Features.Admin.Channel.YouTubePubSub.Get; internal sealed class Handler( IAppDbContext db, IYouTubePubSubService pubSubService, IOptions settings ) : IQueryHandler { public async Task Handle(Query request, CancellationToken ct) { var subscribedIds = (await pubSubService.GetSubscribedChannelIdsAsync(ct)).ToHashSet(); // DB의 YouTube 연동 채널 전체 (활성/비활성 모두) var channels = await db.Channel.AsNoTracking() .Where(c => c.YouTubeChannelID != null && c.YouTubeChannelID != "") .OrderByDescending(c => c.IsActive) .ThenBy(c => c.Name) .Select(c => new { c.ID, c.YouTubeChannelID, c.Name, c.Handle, c.ThumbnailUrl, c.IsActive }) .ToListAsync(ct); var items = new List(channels.Count + subscribedIds.Count); var coveredIds = new HashSet(); // DB 채널 기준 표시 (구독 여부 표시) foreach (var c in channels) { var ytId = c.YouTubeChannelID!; items.Add(new SubscriptionItem( ytId, c.ID, c.Name, c.Handle, c.ThumbnailUrl, true, c.IsActive, subscribedIds.Contains(ytId) )); coveredIds.Add(ytId); } // DB에 없는데 Redis Set에 남아있는 "고아 구독" 표시 foreach (var ytId in subscribedIds.Where(id => !coveredIds.Contains(id))) { items.Add(new SubscriptionItem(ytId, null, null, null, null, false, false, true)); } var subscribedCount = items.Count(x => x.IsSubscribed); return new Response(items, items.Count, subscribedCount, settings.Value.YouTube.CallbackUrl); } }