using GmRelay.Shared.Domain; using GmRelay.Shared.Rendering; using NetCord; using NetCord.Rest; namespace GmRelay.DiscordBot.Rendering; public static class DiscordSessionBatchRenderer { public static (IReadOnlyList Embeds, IReadOnlyList ActionRows) Render(SessionBatchViewModel view) { var embeds = new List(); var actionRows = new List(); foreach (var session in view.Sessions) { var embed = BuildEmbed(view.Title, session); embeds.Add(embed); if (session.AvailableActions.Count > 0) { var actionRow = new ActionRowProperties(); foreach (var action in session.AvailableActions) { actionRow.Add(new ButtonProperties( $"{action.ActionKey}:{action.SessionId}", action.Label, ButtonStyle.Primary)); } actionRows.Add(actionRow); } } return (embeds, actionRows); } private static EmbedProperties BuildEmbed(string title, SessionViewItem session) { var embed = new EmbedProperties() .WithTitle($"{title} — {session.ScheduledAt.FormatMoscow()}"); if (SessionStatus.IsCancelled(session.Status)) { embed = embed.WithDescription("❌ Сессия отменена"); } else { embed = embed.WithDescription(BuildPlayerDescription(session)); } var fields = new List { new EmbedFieldProperties() .WithName("👥 Заполненность") .WithValue(session.MaxPlayers.HasValue ? $"{session.ActivePlayerCount}/{session.MaxPlayers.Value}" : $"{session.ActivePlayerCount}") .WithInline(), new EmbedFieldProperties() .WithName("⏳ Лист ожидания") .WithValue(session.WaitlistedPlayers.Count > 0 ? session.WaitlistedPlayers.Count.ToString() : "—") .WithInline(), new EmbedFieldProperties() .WithName("📊 Статус") .WithValue(FormatStatus(session.Status)) .WithInline() }; var embedUrl = DiscordEmbedUrls.NormalizeHttpUrl(session.JoinLink); if (embedUrl is not null) { embed = embed.WithUrl(embedUrl); } embed = embed.WithColor(GetColor(session)); embed = embed.AddFields(fields); return embed; } private static string BuildPlayerDescription(SessionViewItem session) { if (session.ActivePlayers.Count == 0) return "👥 Пока никто не записался"; var lines = session.ActivePlayers .Select(p => $"• {p.DisplayName}") .ToList(); if (session.WaitlistedPlayers.Count > 0) { lines.Add(""); lines.Add($"⏳ Лист ожидания ({session.WaitlistedPlayers.Count}):"); lines.AddRange(session.WaitlistedPlayers.Select(p => $"• {p.DisplayName}")); } return string.Join('\n', lines); } private static string FormatStatus(string status) => status switch { SessionStatus.Planned => "Запланирована", SessionStatus.ConfirmationSent => "Ожидает подтверждения", SessionStatus.Confirmed => "Подтверждена", SessionStatus.Cancelled => "Отменена", _ => status }; private static Color GetColor(SessionViewItem session) { if (SessionStatus.IsCancelled(session.Status)) return new Color(0xED4245); if (session.Status == SessionStatus.Confirmed) return new Color(0x5865F2); if (session.MaxPlayers.HasValue && session.ActivePlayerCount >= session.MaxPlayers.Value) return new Color(0xFEE75C); return new Color(0x57F287); } }