using LiteCqrs;
using Microsoft.EntityFrameworkCore;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Common.Models;
namespace TeleWave.Application.Notifications.Subscribers;
///
/// Кто подписан и на что. Нужен не ради красоты: рассылка уходит в чужие чаты, и админ должен
/// видеть список — иначе «бот кому-то что-то шлёт» проверяется только по логам Telegram.
///
public sealed class ListTelegramSubscribersQueryHandler(
IAppDbContext dbContext,
IIdentityService identity
) : IQueryHandler>>
{
public async Task>> Handle(
ListTelegramSubscribersQuery query,
CancellationToken cancellationToken
)
{
var subscribers = await dbContext
.TelegramSubscribers.AsNoTracking()
.Include(s => s.Subscriptions)
.OrderByDescending(s => s.LastSeenAt ?? s.CreatedAt)
.ToListAsync(cancellationToken);
var channelNames = await dbContext
.Channels.AsNoTracking()
.ToDictionaryAsync(c => c.Id, c => c.Name, cancellationToken);
// Имена пользователей — через порт: Identity живёт в инфраструктуре, и таблицы его
// прикладной слой не видит.
var userNames = new Dictionary();
foreach (var userId in subscribers.Select(s => s.UserId).Distinct())
{
if (await identity.GetProfileAsync(userId, cancellationToken) is { } profile)
userNames[userId] = profile.UserName;
}
var result = subscribers
.Select(s => new TelegramSubscriberDto(
s.Id,
s.ChatId,
s.DisplayName,
userNames.GetValueOrDefault(s.UserId),
s.IsStopped,
s.CreatedAt,
s.LastSeenAt,
s.Subscriptions.GroupBy(x => x.ChannelId)
.Select(g => new TelegramSubscriptionDto(
g.Key,
// Канал могли удалить — подписки на него остаются висеть, и это надо видеть.
channelNames.GetValueOrDefault(g.Key) ?? "—",
g.Select(x => x.Kind.ToString()).OrderBy(x => x).ToList()
))
.ToList()
))
.ToList();
return Result.Success>(result);
}
}