diff --git a/src/GmRelay.Bot/Features/Sessions/CreateSession/Wizard/ITelegramWizardMessenger.cs b/src/GmRelay.Bot/Features/Sessions/CreateSession/Wizard/ITelegramWizardMessenger.cs new file mode 100644 index 0000000..86ac0c1 --- /dev/null +++ b/src/GmRelay.Bot/Features/Sessions/CreateSession/Wizard/ITelegramWizardMessenger.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace GmRelay.Bot.Features.Sessions.CreateSession.Wizard; + +public sealed record WizardClubOption(Guid ClubId, string Name); + +public interface ITelegramWizardMessenger +{ + Task EditMessageTextAsync(long chatId, int? messageThreadId, long messageId, string text, Telegram.Bot.Types.ReplyMarkups.InlineKeyboardMarkup keyboard, CancellationToken ct); + Task SendGroupMessageAsync(long chatId, int? messageThreadId, string text, Telegram.Bot.Types.ReplyMarkups.InlineKeyboardMarkup keyboard, CancellationToken ct); + Task AnswerCallbackAsync(string callbackId, string? text, CancellationToken ct); + Task> GetGmClubsAsync(long ownerTelegramId, CancellationToken ct); +} diff --git a/src/GmRelay.Bot/Features/Sessions/CreateSession/Wizard/TelegramWizardMessenger.cs b/src/GmRelay.Bot/Features/Sessions/CreateSession/Wizard/TelegramWizardMessenger.cs new file mode 100644 index 0000000..e671e02 --- /dev/null +++ b/src/GmRelay.Bot/Features/Sessions/CreateSession/Wizard/TelegramWizardMessenger.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Dapper; +using Npgsql; +using Telegram.Bot; +using Telegram.Bot.Types.ReplyMarkups; + +namespace GmRelay.Bot.Features.Sessions.CreateSession.Wizard; + +public sealed class TelegramWizardMessenger( + ITelegramBotClient bot, + NpgsqlDataSource dataSource) : ITelegramWizardMessenger +{ + public async Task EditMessageTextAsync( + long chatId, int? messageThreadId, long messageId, string text, + InlineKeyboardMarkup keyboard, CancellationToken ct) + { + var msg = await bot.EditMessageText( + chatId: chatId, + messageId: (int)messageId, + text: text, + replyMarkup: keyboard, + cancellationToken: ct); + return msg.MessageId; + } + + public async Task SendGroupMessageAsync( + long chatId, int? messageThreadId, string text, + InlineKeyboardMarkup keyboard, CancellationToken ct) + { + var msg = await bot.SendMessage( + chatId: chatId, + text: text, + messageThreadId: messageThreadId, + replyMarkup: keyboard, + cancellationToken: ct); + return msg.MessageId; + } + + public async Task AnswerCallbackAsync(string callbackId, string? text, CancellationToken ct) + { + await bot.AnswerCallbackQuery(callbackId, text: text, cancellationToken: ct); + } + + public async Task> GetGmClubsAsync(long ownerTelegramId, CancellationToken ct) + { + // Adjusted from the plan: this codebase models "clubs" as game_groups + // (V001 created game_groups; V026 added public_slug; no `clubs` table exists, + // and game_groups has no `club_id` FK). The picker therefore returns the + // game_groups the owner manages as a GM (via group_managers), matching + // the WizardClubOption contract (UUID id, name) used downstream. + const string sql = """ + SELECT g.id AS ClubId, + g.name AS Name + FROM game_groups g + JOIN group_managers gm ON gm.group_id = g.id + JOIN players p ON p.id = gm.player_id + WHERE p.platform = 'Telegram' + AND p.external_user_id = @ExternalId + GROUP BY g.id, g.name + ORDER BY g.name + """; + await using var connection = await dataSource.OpenConnectionAsync(ct); + var rows = await connection.QueryAsync( + new CommandDefinition(sql, new { ExternalId = ownerTelegramId.ToString() }, cancellationToken: ct)); + return rows.AsList(); + } +}