using GmRelay.Shared.Domain; using Telegram.Bot.Types.ReplyMarkups; namespace GmRelay.Shared.Rendering; public sealed record SessionBatchDto(Guid SessionId, DateTime ScheduledAt, string Status, int? MaxPlayers); public sealed record ParticipantBatchDto(Guid SessionId, string DisplayName, string? TelegramUsername, string RegistrationStatus); public static class SessionBatchRenderer { public static (string Text, InlineKeyboardMarkup Markup) Render( string title, IReadOnlyList sessions, IReadOnlyList participants) { var activeSessions = sessions.OrderBy(s => s.ScheduledAt).ToList(); var messageText = $"🎲 Новые игры: {System.Net.WebUtility.HtmlEncode(title)}\n\n" + $"Расписание:\n\n"; var buttons = new List(); foreach (var session in activeSessions) { var sessionPlayers = participants .Where(p => p.SessionId == session.SessionId && p.RegistrationStatus == ParticipantRegistrationStatus.Active) .ToList(); var waitlistedPlayers = participants .Where(p => p.SessionId == session.SessionId && p.RegistrationStatus == ParticipantRegistrationStatus.Waitlisted) .ToList(); messageText += $"📅 {session.ScheduledAt.FormatMoscow()}\n"; messageText += session.MaxPlayers.HasValue ? $"👥 Места: {sessionPlayers.Count}/{session.MaxPlayers.Value}\n" : $"👥 Игроки ({sessionPlayers.Count}):\n"; if (sessionPlayers.Count > 0) { messageText += string.Join("\n", sessionPlayers.Select(p => $" 👤 {(p.TelegramUsername != null ? "@" + p.TelegramUsername : p.DisplayName)}")) + "\n"; } else { messageText += " Пока никто не записался\n"; } if (waitlistedPlayers.Count > 0) { messageText += $"⏳ Лист ожидания ({waitlistedPlayers.Count}):\n"; messageText += string.Join("\n", waitlistedPlayers.Select(p => $" ⏱ {(p.TelegramUsername != null ? "@" + p.TelegramUsername : p.DisplayName)}")) + "\n"; } if (SessionStatus.IsCancelled(session.Status)) { messageText += "❌ Сессия отменена\n\n"; } else { messageText += "\n"; var dateTitle = session.ScheduledAt.FormatMoscowShort(); buttons.Add(new[] { InlineKeyboardButton.WithCallbackData(GetJoinButtonText(session, sessionPlayers.Count, dateTitle), $"join_session:{session.SessionId}"), InlineKeyboardButton.WithCallbackData($"❌ Отменить {dateTitle} (ГМ)", $"cancel_session:{session.SessionId}"), InlineKeyboardButton.WithCallbackData($"⏰ (ГМ)", $"reschedule_session:{session.SessionId}") } .Concat(SessionCapacityRules.CanPromoteWaitlistedPlayer(session.MaxPlayers, sessionPlayers.Count, waitlistedPlayers.Count) ? [InlineKeyboardButton.WithCallbackData($"⬆️ Из ожидания {dateTitle} (ГМ)", $"promote_waitlist:{session.SessionId}")] : []) .ToArray()); } } return (messageText, new InlineKeyboardMarkup(buttons)); } private static string GetJoinButtonText(SessionBatchDto session, int activePlayers, string dateTitle) { if (session.MaxPlayers.HasValue && activePlayers >= session.MaxPlayers.Value) { return $"⏳ В лист ожидания {dateTitle}"; } return $"✋ На {dateTitle}"; } }