using System;
using System.Globalization;
using GmRelay.Shared.Features.Sessions.CreateSession.Wizard;
using Telegram.Bot.Types;

namespace GmRelay.Bot.Features.Sessions.CreateSession.Wizard;

/// <summary>
/// Converts a Telegram <see cref="Update"/> into the
/// platform-neutral <see cref="WizardInteraction"/> consumed by
/// <see cref="GameCreationWizard"/>. The mapping is the only place in
/// the bot that knows about both <c>Telegram.Bot.Types</c> and the
/// shared wizard contract, so a future Discord adapter can do the same
/// for its native event without changing the wizard core.
/// </summary>
public static class WizardInteractionMapper
{
    /// <summary>
    /// Returns <c>true</c> if <paramref name="update"/> carries a
    /// wizard-relevant interaction (text message, photo, or
    /// callback). Side-effect-free: the wizard state is not touched.
    /// </summary>
    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;
    }
}
