using System.Collections.Generic;
using System.Linq;
using GmRelay.DiscordBot.Rendering;
using GmRelay.Shared.Domain;
using GmRelay.Shared.Features.Sessions.CreateSession.Wizard;
using NetCord;
using NetCord.Rest;
using NetCord.Services.ComponentInteractions;

namespace GmRelay.DiscordBot.Features.Sessions.Wizard;

/// <summary>
/// Renders a wizard step into a Discord embed + components row + an
/// optional modal popup. Lives in the DiscordBot project because the
/// platform-neutral <see cref="WizardStepViewBuilder"/> doesn't know
/// about embeds, action rows, or modals.
///
/// The renderer also exposes <see cref="OpenModal"/> so the slash
/// command can return a "popup" response to the user (Telegram's
/// "ForceReply" equivalent). Discord modals are limited to 5 components
/// (typically labels wrapping text inputs) and a 45-character title.
/// </summary>
public static class DiscordWizardStep
{
    /// <summary>
    /// Discord custom-id budget is 100 characters. We pad our own
    /// identifiers to stay under it.
    /// </summary>
    public const int MaxCustomIdLength = 100;

    /// <summary>
    /// Sentinel returned in <see cref="DiscordWizardRender.OpenModalStep"/>
    /// when the renderer wants the interaction module to open a modal
    /// for the given step. The step name is the <see cref="WizardStepNames"/>
    /// value (e.g. <c>Title</c>, <c>DateTime</c>).
    /// </summary>
    public sealed record DiscordWizardRender(
        string EmbedTitle,
        string EmbedDescription,
        IReadOnlyList<IMessageComponentProperties> Components,
        string? OpenModalStep);

    /// <summary>
    /// Build the embed + components for a wizard step. The caller is
    /// responsible for sending the message via
    /// <see cref="DiscordWizardMessenger"/>.
    /// </summary>
    public static DiscordWizardRender Render(
        WizardDraft draft,
        WizardPayload payload,
        IReadOnlyList<WizardClubOption>? clubs = null)
    {
        return draft.Step switch
        {
            WizardStepNames.Type => RenderType(),
            WizardStepNames.Title => RenderTitle(),
            WizardStepNames.Description => RenderDescription(),
            WizardStepNames.Cover => RenderCover(),
            WizardStepNames.System => RenderSystem(),
            WizardStepNames.Duration => RenderDuration(),
            WizardStepNames.DateTime => RenderDateTime(),
            WizardStepNames.Capacity => RenderCapacity(),
            WizardStepNames.Visibility => RenderVisibility(),
            WizardStepNames.PickClub => RenderPickClub(clubs ?? System.Array.Empty<WizardClubOption>()),
            WizardStepNames.Publish => RenderPublish(),
            WizardStepNames.Confirm => RenderConfirm(payload),

            WizardStepNames.PoolSystemDuration => RenderPoolSystemDuration(),
            WizardStepNames.PoolAddSlots => RenderPoolAddSlots(payload),
            WizardStepNames.PoolSlotDateTime => RenderPoolSlotDateTime(),
            WizardStepNames.PoolSlotCapacity => RenderPoolSlotCapacity(),
            WizardStepNames.PoolConfirm => RenderPoolConfirm(payload),

            _ => throw new System.InvalidOperationException($"Unknown wizard step: {draft.Step}"),
        };
    }

    // ── Custom-id helpers ─────────────────────────────────────────────
    // Three custom-id shapes for buttons, all with the literal "wizard" prefix
    // that the NetCord [ComponentInteraction("wizard")] matcher strips off.
    // After prefix-strip the dispatcher receives the suffix as `args`.
    //
    //   Choice      : wizard:btn:choice:<step>:<value>   → wizard's ApplyChoice
    //   Control     : wizard:btn:<action>:1              → dispatcher special case
    //   Modal trig. : wizard:btn:modal:<modalStep>       → dispatcher opens modal
    //
    // The renderer's helpers below enforce these shapes so the dispatcher
    // parser and the wizard callbacks stay in lockstep.
    public static string ChoiceButtonCustomId(string step, string value) =>
        $"wizard:btn:choice:{step}:{value}";

    public static string ControlButtonCustomId(string action) =>
        $"wizard:btn:{action}:1";

    public static string ModalTriggerButtonCustomId(string modalStep) =>
        $"wizard:btn:modal:{modalStep}";

    public static string SelectCustomId(string step) => $"wizard:select:{step}";

    public static string ModalCustomId(string step) => $"wizard:modal:{step}";

    public static bool TryParseButtonCustomId(string customId, out string step, out string value)
    {
        step = value = string.Empty;
        var parts = customId.Split(':', 5);
        if (parts.Length < 5 || parts[0] != "wizard" || parts[1] != "btn" || parts[2] != "choice")
        {
            return false;
        }
        step = parts[3];
        value = parts[4];
        return true;
    }

    public static bool TryParseSelectCustomId(string customId, out string step)
    {
        step = string.Empty;
        var parts = customId.Split(':', 3);
        return parts.Length >= 3 && parts[0] == "wizard" && parts[1] == "select" && (step = parts[2]) is not null;
    }

    public static bool TryParseModalCustomId(string customId, out string step)
    {
        step = string.Empty;
        var parts = customId.Split(':', 3);
        return parts.Length >= 3 && parts[0] == "wizard" && parts[1] == "modal" && (step = parts[2]) is not null;
    }

    // ── Helpers ───────────────────────────────────────────────────────
    // Three button factories, one per custom-id shape (see ChoiceButtonCustomId
    // comment above). RenderX() uses these to build rows; the call site
    // determines which kind of button each row needs.
    private static ButtonProperties ChoiceBtn(string label, string step, string value, ButtonStyle style = ButtonStyle.Secondary)
    {
        var cid = ChoiceButtonCustomId(step, value);
        EnsureCustomIdFits(cid);
        return new ButtonProperties(cid, label, style);
    }

    private static ButtonProperties ControlBtn(string label, string action, ButtonStyle style = ButtonStyle.Secondary)
    {
        var cid = ControlButtonCustomId(action);
        EnsureCustomIdFits(cid);
        return new ButtonProperties(cid, label, style);
    }

    private static ButtonProperties ModalTriggerBtn(string label, string modalStep, ButtonStyle style = ButtonStyle.Secondary)
    {
        var cid = ModalTriggerButtonCustomId(modalStep);
        EnsureCustomIdFits(cid);
        return new ButtonProperties(cid, label, style);
    }

    private static ActionRowProperties Row(params IActionRowComponentProperties[] components)
    {
        var row = new ActionRowProperties();
        foreach (var c in components)
        {
            row.Add(c);
        }
        return row;
    }

    /// <summary>
    /// Wrap a list of top-level message components (action rows and
    /// select menus) into a single <see cref="IReadOnlyList{IMessageComponentProperties}"/>
    /// for <c>MessageProperties.WithComponents</c>.
    /// </summary>
    private static IReadOnlyList<IMessageComponentProperties> Comps(params IMessageComponentProperties[] items) =>
        items;

    private static void EnsureCustomIdFits(string customId)
    {
        if (customId.Length > MaxCustomIdLength)
        {
            throw new System.InvalidOperationException(
                $"Custom id '{customId}' is {customId.Length} chars; Discord limit is {MaxCustomIdLength}.");
        }
    }

    // ── Single-game steps ─────────────────────────────────────────────
    private static DiscordWizardRender RenderType() => new(
        "🎲 Создание игровой сессии",
        "Выберите тип: одна игра или пул.",
        new IMessageComponentProperties[] { Row(ChoiceBtn("🎯 Одну игру", WizardStepNames.Type, "single", ButtonStyle.Primary),
                    ChoiceBtn("📅 Пул игр", WizardStepNames.Type, "pool", ButtonStyle.Primary),
                    ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)) },
        OpenModalStep: null);

    private static DiscordWizardRender RenderTitle() => new(
        "📝 Название",
        "Введите название игры в модальном окне.",
        new IMessageComponentProperties[] { Row(ControlBtn("⬅️ Назад", "back"),
                    ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)) },
        OpenModalStep: WizardStepNames.Title);

    private static DiscordWizardRender RenderDescription() => new(
        "📄 Описание",
        "Введите описание (или «-», чтобы пропустить).",
        new IMessageComponentProperties[] { Row(ChoiceBtn("⏭ Пропустить", WizardStepNames.Description, "-"),
                    ControlBtn("⬅️ Назад", "back"),
                    ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)) },
        OpenModalStep: WizardStepNames.Description);

    private static DiscordWizardRender RenderCover() => new(
        "🖼 Обложка",
        "Введите URL картинки (или «-», чтобы пропустить).",
        new IMessageComponentProperties[] { Row(ChoiceBtn("⏭ Пропустить", WizardStepNames.Cover, "-"),
                    ControlBtn("⬅️ Назад", "back"),
                    ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)) },
        OpenModalStep: WizardStepNames.Cover);

    private static DiscordWizardRender RenderSystem() => new(
        "🎲 Система",
        "Выберите систему.",
        new[]
        {
            Row(ChoiceBtn("D&D 5e", WizardStepNames.System, "Dnd5e"),
                ChoiceBtn("Pathfinder 2e", WizardStepNames.System, "Pathfinder2e"),
                ChoiceBtn("Call of Cthulhu", WizardStepNames.System, "CallOfCthulhu7e"),
                ChoiceBtn("GURPS", WizardStepNames.System, "GURPS"),
                ChoiceBtn("Fate", WizardStepNames.System, "Fate")),
            Row(ModalTriggerBtn("Другое… ✏️", "SystemFreeText", ButtonStyle.Primary),
                ChoiceBtn("⏭ Пропустить", WizardStepNames.System, "_skip"),
                ControlBtn("⬅️ Назад", "back"),
                ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)),
        },
        OpenModalStep: null);

    private static DiscordWizardRender RenderDuration() => new(
        "⏱ Длительность",
        "Выберите длительность (или «Другое…»).",
        new[]
        {
            Row(ChoiceBtn("3 часа", WizardStepNames.Duration, "180"),
                ChoiceBtn("4 часа", WizardStepNames.Duration, "240"),
                ChoiceBtn("5 часов", WizardStepNames.Duration, "300"),
                ChoiceBtn("6 часов", WizardStepNames.Duration, "360")),
            Row(ModalTriggerBtn("Другое… ✏️", "DurationFreeText", ButtonStyle.Primary),
                ChoiceBtn("⏭ Пропустить", WizardStepNames.Duration, "_skip"),
                ControlBtn("⬅️ Назад", "back"),
                ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)),
        },
        OpenModalStep: null);

    private static DiscordWizardRender RenderDateTime() => new(
        "📅 Дата и время",
        "Введите дату в формате ДД.ММ.ГГГГ ЧЧ:ММ (Москва).",
        new IMessageComponentProperties[] { Row(ControlBtn("⬅️ Назад", "back"),
                    ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)) },
        OpenModalStep: WizardStepNames.DateTime);

    private static DiscordWizardRender RenderCapacity() => new(
        "👥 Лимит мест",
        "Введите лимит (1..50), выберите waitlist или сразу «♾ Без лимита».",
        new[]
        {
            Row(ChoiceBtn("✅ Waitlist вкл", WizardStepNames.Capacity, "waitlist:on", ButtonStyle.Success),
                ChoiceBtn("❌ Без waitlist", WizardStepNames.Capacity, "waitlist:off", ButtonStyle.Danger)),
            Row(ChoiceBtn("♾ Без лимита", WizardStepNames.Capacity, "no_limit", ButtonStyle.Primary)),
            Row(ControlBtn("⬅️ Назад", "back"),
                ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)),
        },
        OpenModalStep: WizardStepNames.Capacity);

    private static DiscordWizardRender RenderVisibility() => new(
        "🔒 Видимость",
        "Выберите, кто увидит сессию.",
        new IMessageComponentProperties[]
        {
            BuildSelectMenu(
                SelectCustomId(WizardStepNames.Visibility),
                "Выберите видимость…",
                new[] { new StringMenuSelectOptionProperties("🌐 Публичная в общем showcase", "public"),
                    new StringMenuSelectOptionProperties("🏠 Публичная в витрине клуба", "club"),
                    new StringMenuSelectOptionProperties("🔐 Только для членов клуба", "members"),
                }),
            Row(ControlBtn("⬅️ Назад", "back"),
                ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)),
        },
        OpenModalStep: null);

    private static DiscordWizardRender RenderPickClub(IReadOnlyList<WizardClubOption> clubs)
    {
        if (clubs.Count == 0)
        {
            return new DiscordWizardRender(
                "🏷 Выбор клуба",
                "У вас нет клубов. Создайте клуб в Web dashboard и вернитесь.",
                new IMessageComponentProperties[] { Row(ControlBtn("⬅️ Назад", "back"),
                            ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)) },
                OpenModalStep: null);
        }
        var options = new List<StringMenuSelectOptionProperties>(clubs.Count);
        foreach (var c in clubs.Take(25))
        {
            options.Add(new StringMenuSelectOptionProperties(c.Name, c.ClubId.ToString()));
        }
        return new DiscordWizardRender(
            "🏷 Выбор клуба",
            "Выберите клуб из списка.",
            new IMessageComponentProperties[]
            {
                BuildSelectMenu(SelectCustomId(WizardStepNames.PickClub), "Выберите клуб…", options),
                Row(ControlBtn("⬅️ Назад", "back"),
                    ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)),
            },
            OpenModalStep: null);
    }

    private static DiscordWizardRender RenderPublish() => new(
        "✨ Публикация",
        "Опубликовать в витрине сейчас?",
        new[]
        {
            Row(ChoiceBtn("✅ Опубликовать", WizardStepNames.Publish, "yes", ButtonStyle.Success),
                ChoiceBtn("📝 Только в чате", WizardStepNames.Publish, "no")),
            Row(ControlBtn("⬅️ Назад", "back"),
                ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)),
        },
        OpenModalStep: null);

    private static DiscordWizardRender RenderConfirm(WizardPayload p) => new(
        "👀 Проверьте перед созданием",
        BuildConfirmDescription(p),
        new[]
        {
            Row(ControlBtn("✅ Создать", "create", ButtonStyle.Success),
                ControlBtn("⬅️ Назад", "back"),
                ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)),
        },
        OpenModalStep: null);

    // ── Pool steps ────────────────────────────────────────────────────
    private static DiscordWizardRender RenderPoolSystemDuration() => new(
        "🎲 Система и длительность пула",
        "Выберите пресет или «Другое…».",
        new IMessageComponentProperties[]
        {
            BuildSelectMenu(
                SelectCustomId(WizardStepNames.PoolSystemDuration),
                "Выберите пресет…",
                new[] { new StringMenuSelectOptionProperties("D&D 5e · 4 ч", "Dnd5e:240"),
                    new StringMenuSelectOptionProperties("Pathfinder 2e · 4 ч", "Pathfinder2e:240"),
                    new StringMenuSelectOptionProperties("Call of Cthulhu · 3 ч", "CallOfCthulhu7e:180"),
                    new StringMenuSelectOptionProperties("GURPS · 4 ч", "GURPS:240"),
                }),
            Row(ModalTriggerBtn("Другое… ✏️", "PoolSystemDurationFreeText", ButtonStyle.Primary),
                ControlBtn("⬅️ Назад", "back"),
                ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)),
        },
        OpenModalStep: null);

    private static DiscordWizardRender RenderPoolAddSlots(WizardPayload p) => new(
        $"📅 Слоты пула «{p.Title}»",
        $"Добавлено: {p.Pool?.Slots.Count ?? 0}.",
        new[]
        {
            Row(ChoiceBtn("➕ Добавить слот", WizardStepNames.PoolAddSlots, "add", ButtonStyle.Primary),
                ChoiceBtn("✅ Готово, к превью", WizardStepNames.PoolAddSlots, "done", ButtonStyle.Success)),
            Row(ControlBtn("⬅️ Назад", "back"),
                ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)),
        },
        OpenModalStep: null);

    private static DiscordWizardRender RenderPoolSlotDateTime() => new(
        "📅 Дата/время слота",
        "Введите дату/время слота (ДД.ММ.ГГГГ ЧЧ:ММ).",
        new IMessageComponentProperties[] { Row(ControlBtn("⬅️ Назад", "back"),
                    ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)) },
        OpenModalStep: WizardStepNames.PoolSlotDateTime);

    private static DiscordWizardRender RenderPoolSlotCapacity() => new(
        "👥 Лимит слотов",
        "Введите лимит (1..50), выберите waitlist или сразу «♾ Без лимита».",
        new[]
        {
            Row(ChoiceBtn("✅ Waitlist вкл", WizardStepNames.PoolSlotCapacity, "waitlist:on", ButtonStyle.Success),
                ChoiceBtn("❌ Без waitlist", WizardStepNames.PoolSlotCapacity, "waitlist:off", ButtonStyle.Danger)),
            Row(ChoiceBtn("♾ Без лимита", WizardStepNames.PoolSlotCapacity, "no_limit", ButtonStyle.Primary)),
            Row(ControlBtn("⬅️ Назад", "back"),
                ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)),
        },
        OpenModalStep: WizardStepNames.PoolSlotCapacity);

    private static DiscordWizardRender RenderPoolConfirm(WizardPayload p) => new(
        "👀 Проверьте пул перед созданием",
        BuildPoolConfirmDescription(p),
        new[]
        {
            Row(ControlBtn("✅ Создать пул", "create", ButtonStyle.Success),
                ControlBtn("⬅️ Назад", "back"),
                ControlBtn("❌ Отмена", "cancel", ButtonStyle.Danger)),
        },
        OpenModalStep: null);

    // ── Builders for embed descriptions and selects ───────────────────
    private static StringMenuProperties BuildSelectMenu(
        string customId,
        string placeholder,
        IReadOnlyList<StringMenuSelectOptionProperties> options)
    {
        EnsureCustomIdFits(customId);
        return new StringMenuProperties(customId, options)
        {
            Placeholder = placeholder,
        };
    }

    private static string BuildConfirmDescription(WizardPayload p)
    {
        var sb = new System.Text.StringBuilder();
        sb.Append("🎲 ").AppendLine(p.Title);
        if (!string.IsNullOrEmpty(p.Description)) sb.Append("📄 ").AppendLine(p.Description);
        if (!string.IsNullOrEmpty(p.System)) sb.Append("🎲 Система: ").AppendLine(p.System);
        if (p.DurationMinutes.HasValue) sb.Append("⏱ Длительность: ").Append(p.DurationMinutes.Value / 60).AppendLine(" ч");
        if (p.Single?.ScheduledAt is { } at) sb.Append("📅 ").AppendLine(at.FormatMoscow());
        if (p.Single?.MaxPlayers is { } mp)
        {
            sb.Append("👥 Мест: ").Append(mp).Append(", waitlist ").Append(p.Waitlist == true ? "вкл" : "выкл").AppendLine();
        }
        else if (p.Type == WizardCreationType.Single)
        {
            sb.Append("👥 Без лимита, waitlist ").Append(p.Waitlist == true ? "вкл" : "выкл").AppendLine();
        }
        sb.Append("🔒 Видимость: ").AppendLine(RenderVisibilityText(p.Visibility));
        return sb.ToString();
    }

    private static string BuildPoolConfirmDescription(WizardPayload p)
    {
        var sb = new System.Text.StringBuilder();
        sb.Append("📝 ").AppendLine(p.Title);
        if (!string.IsNullOrEmpty(p.Description)) sb.Append("📄 ").AppendLine(p.Description);
        if (!string.IsNullOrEmpty(p.System)) sb.Append("🎲 Система: ").AppendLine(p.System);
        if (p.DurationMinutes.HasValue) sb.Append("⏱ Длительность: ").Append(p.DurationMinutes.Value / 60).AppendLine(" ч");
        sb.Append("🔒 Видимость: ").AppendLine(RenderVisibilityText(p.Visibility));
        sb.Append("Слоты (").Append(p.Pool?.Slots.Count ?? 0).AppendLine("):");
        if (p.Pool is not null)
        {
            foreach (var s in p.Pool.Slots)
            {
                sb.Append("  • ").Append(s.ScheduledAt.FormatMoscow())
                    .Append(" — мест ").Append(s.MaxPlayers)
                    .Append(", waitlist ").Append(s.Waitlist ? "вкл" : "выкл")
                    .AppendLine();
            }
        }
        return sb.ToString();
    }

    private static string RenderVisibilityText(WizardVisibility? v) => v switch
    {
        WizardVisibility.Public => "публичная в общем showcase",
        WizardVisibility.Club => "публичная в витрине клуба",
        WizardVisibility.Members => "только для членов клуба",
        _ => "не задана",
    };

    // ── Modal builders ────────────────────────────────────────────────
    /// <summary>
    /// Build a <see cref="ModalProperties"/> for the given wizard step.
    /// The wizard step's <c>openModal</c> value drives which modal we
    /// emit. Returns <c>null</c> if no modal is required for the step.
    /// </summary>
    public static ModalProperties? BuildModal(string step, string? draftTitle)
    {
        return step switch
        {
            WizardStepNames.Title => new ModalProperties(
                ModalCustomId(WizardStepNames.Title),
                "📝 Название игры",
                new IModalComponentProperties[]
                {
                    new LabelProperties(
                        "Название",
                        new TextInputProperties(ModalCustomId(WizardStepNames.Title), TextInputStyle.Short)
                        {
                            Placeholder = "Например: D&D 5e, Проклятие Страда",
                            MinLength = 1,
                            MaxLength = WizardStepLimits.MaxTitleLength,
                            Required = true,
                        }),
                }),
            WizardStepNames.Description => new ModalProperties(
                ModalCustomId(WizardStepNames.Description),
                "📄 Описание",
                new IModalComponentProperties[]
                {
                    new LabelProperties(
                        "Описание",
                        new TextInputProperties(ModalCustomId(WizardStepNames.Description), TextInputStyle.Paragraph)
                        {
                            Placeholder = "Опишите сценарий / сеттинг. «-» чтобы пропустить.",
                            MaxLength = WizardStepLimits.MaxDescriptionLength,
                            Required = true,
                        }),
                }),
            WizardStepNames.Cover => new ModalProperties(
                ModalCustomId(WizardStepNames.Cover),
                "🖼 Обложка (URL)",
                new IModalComponentProperties[]
                {
                    new LabelProperties(
                        "URL картинки",
                        new TextInputProperties(ModalCustomId(WizardStepNames.Cover), TextInputStyle.Short)
                        {
                            Placeholder = "https://… или «-» чтобы пропустить",
                            MaxLength = 500,
                            Required = true,
                        }),
                }),
            "SystemFreeText" => new ModalProperties(
                ModalCustomId("SystemFreeText"),
                "🎲 Другая система",
                new IModalComponentProperties[]
                {
                    new LabelProperties(
                        "Система",
                        new TextInputProperties(ModalCustomId("SystemFreeText"), TextInputStyle.Short)
                        {
                            Placeholder = "Свободное название системы",
                            MaxLength = WizardStepLimits.MaxSystemLength,
                            Required = true,
                        }),
                }),
            "DurationFreeText" => new ModalProperties(
                ModalCustomId("DurationFreeText"),
                "⏱ Длительность (часы)",
                new IModalComponentProperties[]
                {
                    new LabelProperties(
                        "Часы",
                        new TextInputProperties(ModalCustomId("DurationFreeText"), TextInputStyle.Short)
                        {
                            Placeholder = "1..12",
                            MaxLength = 4,
                            Required = true,
                        }),
                }),
            WizardStepNames.DateTime => new ModalProperties(
                ModalCustomId(WizardStepNames.DateTime),
                "📅 Дата и время",
                new IModalComponentProperties[]
                {
                    new LabelProperties(
                        "Когда",
                        new TextInputProperties(ModalCustomId(WizardStepNames.DateTime), TextInputStyle.Short)
                        {
                            Placeholder = "ДД.ММ.ГГГГ ЧЧ:ММ",
                            MaxLength = 32,
                            Required = true,
                        }),
                }),
            WizardStepNames.Capacity => new ModalProperties(
                ModalCustomId(WizardStepNames.Capacity),
                "👥 Лимит мест",
                new IModalComponentProperties[]
                {
                    new LabelProperties(
                        "Max players",
                        new TextInputProperties(ModalCustomId(WizardStepNames.Capacity), TextInputStyle.Short)
                        {
                            Placeholder = "1..50",
                            MaxLength = 3,
                            Required = true,
                        }),
                }),
            WizardStepNames.PoolSlotDateTime => new ModalProperties(
                ModalCustomId(WizardStepNames.PoolSlotDateTime),
                "📅 Дата/время слота",
                new IModalComponentProperties[]
                {
                    new LabelProperties(
                        "Когда",
                        new TextInputProperties(ModalCustomId(WizardStepNames.PoolSlotDateTime), TextInputStyle.Short)
                        {
                            Placeholder = "ДД.ММ.ГГГГ ЧЧ:ММ",
                            MaxLength = 32,
                            Required = true,
                        }),
                }),
            WizardStepNames.PoolSlotCapacity => new ModalProperties(
                ModalCustomId(WizardStepNames.PoolSlotCapacity),
                "👥 Лимит слотов",
                new IModalComponentProperties[]
                {
                    new LabelProperties(
                        "Max players",
                        new TextInputProperties(ModalCustomId(WizardStepNames.PoolSlotCapacity), TextInputStyle.Short)
                        {
                            Placeholder = "1..50",
                            MaxLength = 3,
                            Required = true,
                        }),
                }),
            "PoolSystemDurationFreeText" => new ModalProperties(
                ModalCustomId("PoolSystemDurationFreeText"),
                "🎲 Другая система пула",
                new IModalComponentProperties[]
                {
                    new LabelProperties(
                        "Система и длительность",
                        new TextInputProperties(ModalCustomId("PoolSystemDurationFreeText"), TextInputStyle.Short)
                        {
                            Placeholder = "Dnd5e:240 или «Pathfinder 2e:180»",
                            MaxLength = 32,
                            Required = true,
                        }),
                }),
            _ => null,
        };
    }
}
