using System; using System.Globalization; using GmRelay.Shared.Features.Sessions.CreateSession.Wizard; using Telegram.Bot.Types; namespace GmRelay.Bot.Features.Sessions.CreateSession.Wizard; /// /// Converts a Telegram into the /// platform-neutral consumed by /// . The mapping is the only place in /// the bot that knows about both Telegram.Bot.Types and the /// shared wizard contract, so a future Discord adapter can do the same /// for its native event without changing the wizard core. /// public static class WizardInteractionMapper { /// /// Returns true if carries a /// wizard-relevant interaction (text message, photo, or /// callback). Side-effect-free: the wizard state is not touched. /// public static bool TryMap(Update update, out WizardInteraction interaction) { interaction = default!; if (update.CallbackQuery is { } cb && cb.From is not null) { interaction = new WizardInteraction( OwnerId: cb.From.Id.ToString(CultureInfo.InvariantCulture), Text: null, CallbackPayload: cb.Data, PhotoFileId: null, PhotoUrl: null, InteractionId: cb.Id); return true; } if (update.Message is { From: not null } msg) { // The original Telegram wizard dispatched on // `msg.Text is null` to identify a non-text update (photo, // document, sticker, …) and only ran the text pipeline // otherwise. We preserve that semantic: a message that // carries a photo is a photo interaction even if it has a // caption. Text is null for photos; the wizard checks // PhotoFileId separately when Text is null. // // Note: `Message.MessageId` is exposed as a read-only // property in Telegram.Bot, so the mapper cannot embed the // numeric id in the interaction. Text interactions never // need an ack, so the InteractionId is unused for them — // we just emit a stable sentinel. var hasPhoto = msg.Photo is { Length: > 0 }; var text = hasPhoto ? null : msg.Text; var photoFileId = hasPhoto ? msg.Photo![^1].FileId : null; interaction = new WizardInteraction( OwnerId: msg.From!.Id.ToString(CultureInfo.InvariantCulture), Text: text, CallbackPayload: null, PhotoFileId: photoFileId, PhotoUrl: null, InteractionId: "msg"); return true; } return false; } }