using System;
using System.Collections.Generic;
using System.Text;
using GmRelay.Shared.Domain;
using GmRelay.Shared.Features.Sessions.CreateSession.Wizard;
using Telegram.Bot.Types.ReplyMarkups;

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

public static class WizardStep
{
    public const int MaxTitleLength = 200;
    public const int MaxDescriptionLength = 4000;
    public const int MaxSystemLength = 100;
    public const int MaxCapacity = 50;
    public const int MinCapacity = 1;
    public const int MinDurationHours = 1;
    public const int MaxDurationHours = 12;

    public static (string text, InlineKeyboardMarkup keyboard) 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 ?? Array.Empty<WizardClubOption>()),
            WizardStepNames.Publish => RenderPublish(),
            WizardStepNames.Confirm => RenderSingleConfirm(payload),

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

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

    // ── Single-game renderers ──────────────────────────────────────────
    private static (string, InlineKeyboardMarkup) RenderType() => (
        "🎲 Создание новой игровой сессии\n\nЧто создаём?",
        new InlineKeyboardMarkup(new[]
        {
            new[] { InlineKeyboardButton.WithCallbackData("🎯 Одну игру", WizardCallbackData.Choice(WizardStepNames.Type, "single")) },
            new[] { InlineKeyboardButton.WithCallbackData("📅 Пул игр", WizardCallbackData.Choice(WizardStepNames.Type, "pool")) },
            new[] { InlineKeyboardButton.WithCallbackData("❌ Отмена", WizardCallbackData.Cancel()) },
        }));

    private static (string, InlineKeyboardMarkup) RenderTitle() => (
        "📝 Введите название игры одним сообщением.",
        BackCancel());

    private static (string, InlineKeyboardMarkup) RenderDescription() => (
        "📄 Введите описание (или «-», чтобы пропустить).",
        SkipBackCancel());

    private static (string, InlineKeyboardMarkup) RenderCover() => (
        "🖼 Пришлите картинку как вложение или URL (или «-»).",
        SkipBackCancel());

    private static (string, InlineKeyboardMarkup) RenderSystem()
    {
        var buttons = new List<InlineKeyboardButton[]>
        {
            new[] { InlineKeyboardButton.WithCallbackData("D&D 5e",         WizardCallbackData.Choice(WizardStepNames.System, "Dnd5e")) },
            new[] { InlineKeyboardButton.WithCallbackData("Pathfinder 2e",  WizardCallbackData.Choice(WizardStepNames.System, "Pathfinder2e")) },
            new[] { InlineKeyboardButton.WithCallbackData("Call of Cthulhu",WizardCallbackData.Choice(WizardStepNames.System, "CallOfCthulhu7e")) },
            new[] { InlineKeyboardButton.WithCallbackData("GURPS",          WizardCallbackData.Choice(WizardStepNames.System, "GURPS")) },
            new[] { InlineKeyboardButton.WithCallbackData("Fate",           WizardCallbackData.Choice(WizardStepNames.System, "Fate")) },
            new[] { InlineKeyboardButton.WithCallbackData("Другое… ✏️",       WizardCallbackData.Choice(WizardStepNames.System, "_other")) },
            new[] { InlineKeyboardButton.WithCallbackData("⏭ Пропустить",     WizardCallbackData.Choice(WizardStepNames.System, "_skip")) },
        };
        return ("🎲 Выберите систему.", new InlineKeyboardMarkup(buttons).AppendBackCancel());
    }

    private static (string, InlineKeyboardMarkup) RenderDuration() => (
        "⏱ Выберите длительность.",
        new InlineKeyboardMarkup(new[]
        {
            new[] { InlineKeyboardButton.WithCallbackData("3 часа",  WizardCallbackData.Choice(WizardStepNames.Duration, "180")) },
            new[] { InlineKeyboardButton.WithCallbackData("4 часа",  WizardCallbackData.Choice(WizardStepNames.Duration, "240")) },
            new[] { InlineKeyboardButton.WithCallbackData("5 часов", WizardCallbackData.Choice(WizardStepNames.Duration, "300")) },
            new[] { InlineKeyboardButton.WithCallbackData("6 часов", WizardCallbackData.Choice(WizardStepNames.Duration, "360")) },
            new[] { InlineKeyboardButton.WithCallbackData("Другое… ✏️", WizardCallbackData.Choice(WizardStepNames.Duration, "_other")) },
            new[] { InlineKeyboardButton.WithCallbackData("⏭ Пропустить", WizardCallbackData.Choice(WizardStepNames.Duration, "_skip")) },
        }).AppendBackCancel());

    private static (string, InlineKeyboardMarkup) RenderDateTime() => (
        "📅 Введите дату и время в формате ДД.ММ.ГГГГ ЧЧ:ММ (Москва).",
        BackCancel());

    private static (string, InlineKeyboardMarkup) RenderCapacity() => (
        "👥 Введите лимит мест (1..50) одним числом.\nЗатем нажмите кнопку waitlist.",
        new InlineKeyboardMarkup(new[]
        {
            new[] { InlineKeyboardButton.WithCallbackData("✅ Waitlist вкл",   WizardCallbackData.Choice(WizardStepNames.Capacity, "waitlist:on")) },
            new[] { InlineKeyboardButton.WithCallbackData("❌ Без waitlist",   WizardCallbackData.Choice(WizardStepNames.Capacity, "waitlist:off")) },
        }).AppendBackCancel());

    private static (string, InlineKeyboardMarkup) RenderVisibility() => (
        "🔒 Выберите видимость.",
        new InlineKeyboardMarkup(new[]
        {
            new[] { InlineKeyboardButton.WithCallbackData("🌐 Публичная в общем showcase", WizardCallbackData.Choice(WizardStepNames.Visibility, "public")) },
            new[] { InlineKeyboardButton.WithCallbackData("🏠 Публичная в витрине клуба", WizardCallbackData.Choice(WizardStepNames.Visibility, "club")) },
            new[] { InlineKeyboardButton.WithCallbackData("🔐 Только для членов клуба",   WizardCallbackData.Choice(WizardStepNames.Visibility, "members")) },
            new[] { InlineKeyboardButton.WithCallbackData("🏷 Выбрать клуб…",             WizardCallbackData.Choice(WizardStepNames.Visibility, "pickclub")) },
        }).AppendBackCancel());

    private static (string, InlineKeyboardMarkup) RenderPickClub(IReadOnlyList<WizardClubOption> clubs)
    {
        if (clubs.Count == 0)
        {
            return (
                "🏷 У вас нет клубов. Создайте клуб в Web dashboard и вернитесь.",
                BackCancel());
        }
        var rows = new List<InlineKeyboardButton[]>();
        foreach (var club in clubs)
        {
            rows.Add(new[]
            {
                InlineKeyboardButton.WithCallbackData(club.Name, WizardCallbackData.Choice(WizardStepNames.PickClub, club.ClubId.ToString()))
            });
        }
        return ("🏷 Выберите клуб:", new InlineKeyboardMarkup(rows).AppendBackCancel());
    }

    private static (string, InlineKeyboardMarkup) RenderPublish() => (
        "✨ Опубликовать в витрине сейчас?",
        new InlineKeyboardMarkup(new[]
        {
            new[] { InlineKeyboardButton.WithCallbackData("✅ Опубликовать",  WizardCallbackData.Choice(WizardStepNames.Publish, "yes")) },
            new[] { InlineKeyboardButton.WithCallbackData("📝 Только в чате", WizardCallbackData.Choice(WizardStepNames.Publish, "no")) },
        }).AppendBackCancel());

    private static (string, InlineKeyboardMarkup) RenderSingleConfirm(WizardPayload p)
    {
        var sb = new StringBuilder();
        sb.AppendLine("👀 Проверьте перед созданием:");
        sb.AppendLine();
        sb.AppendLine($"🎲 {p.Title}");
        if (!string.IsNullOrEmpty(p.Description)) sb.AppendLine($"📄 {p.Description}");
        if (!string.IsNullOrEmpty(p.System)) sb.AppendLine($"🎲 Система: {p.System}");
        if (p.DurationMinutes.HasValue) sb.AppendLine($"⏱ Длительность: {p.DurationMinutes / 60} ч");
        if (p.Single?.ScheduledAt is { } at) sb.AppendLine($"📅 {at.FormatMoscow()} (МСК)");
        if (p.Single?.MaxPlayers is { } mp) sb.AppendLine($"👥 Мест: {mp}, waitlist {(p.Waitlist == true ? "вкл" : "выкл")}");
        sb.AppendLine($"🔒 Видимость: {RenderVisibilityText(p.Visibility)}");
        return (sb.ToString(), new InlineKeyboardMarkup(new[]
        {
            new[] { InlineKeyboardButton.WithCallbackData("✅ Создать", WizardCallbackData.Create()) },
            new[] { InlineKeyboardButton.WithCallbackData("⬅️ Назад",   WizardCallbackData.Back()) },
            new[] { InlineKeyboardButton.WithCallbackData("❌ Отмена",  WizardCallbackData.Cancel()) },
        }));
    }

    // ── Pool renderers ─────────────────────────────────────────────────
    private static (string, InlineKeyboardMarkup) RenderPoolSystemDuration() => (
        "🎲 Выберите систему и длительность пула.",
        new InlineKeyboardMarkup(new[]
        {
            new[] { InlineKeyboardButton.WithCallbackData("D&D 5e · 4 ч",         WizardCallbackData.Choice(WizardStepNames.PoolSystemDuration, "Dnd5e:240")) },
            new[] { InlineKeyboardButton.WithCallbackData("Pathfinder 2e · 4 ч",  WizardCallbackData.Choice(WizardStepNames.PoolSystemDuration, "Pathfinder2e:240")) },
            new[] { InlineKeyboardButton.WithCallbackData("Call of Cthulhu · 3 ч",WizardCallbackData.Choice(WizardStepNames.PoolSystemDuration, "CallOfCthulhu7e:180")) },
            new[] { InlineKeyboardButton.WithCallbackData("GURPS · 4 ч",          WizardCallbackData.Choice(WizardStepNames.PoolSystemDuration, "GURPS:240")) },
            new[] { InlineKeyboardButton.WithCallbackData("Другое… ✏️",             WizardCallbackData.Choice(WizardStepNames.PoolSystemDuration, "_custom")) },
        }).AppendBackCancel());

    private static (string, InlineKeyboardMarkup) RenderPoolAddSlots(WizardPayload p) => (
        $"📅 Слоты пула «{p.Title}»\n\nДобавлено: {(p.Pool?.Slots.Count ?? 0)}",
        new InlineKeyboardMarkup(new[]
        {
            new[] { InlineKeyboardButton.WithCallbackData("➕ Добавить слот",      WizardCallbackData.Choice(WizardStepNames.PoolAddSlots, "add")) },
            new[] { InlineKeyboardButton.WithCallbackData("✅ Готово, к превью",  WizardCallbackData.Choice(WizardStepNames.PoolAddSlots, "done")) },
        }).AppendBackCancel());

    private static (string, InlineKeyboardMarkup) RenderPoolSlotDateTime() => (
        "📅 Введите дату/время слота (ДД.ММ.ГГГГ ЧЧ:ММ).",
        BackCancel());

    private static (string, InlineKeyboardMarkup) RenderPoolSlotCapacity() => (
        "👥 Введите лимит мест (1..50) и выберите waitlist.",
        new InlineKeyboardMarkup(new[]
        {
            new[] { InlineKeyboardButton.WithCallbackData("✅ Waitlist вкл",  WizardCallbackData.Choice(WizardStepNames.PoolSlotCapacity, "waitlist:on")) },
            new[] { InlineKeyboardButton.WithCallbackData("❌ Без waitlist",  WizardCallbackData.Choice(WizardStepNames.PoolSlotCapacity, "waitlist:off")) },
        }).AppendBackCancel());

    private static (string, InlineKeyboardMarkup) RenderPoolConfirm(WizardPayload p)
    {
        var sb = new StringBuilder();
        sb.AppendLine("👀 Проверьте пул перед созданием:");
        sb.AppendLine();
        sb.AppendLine($"📝 {p.Title}");
        if (!string.IsNullOrEmpty(p.Description)) sb.AppendLine($"📄 {p.Description}");
        if (!string.IsNullOrEmpty(p.System)) sb.AppendLine($"🎲 Система: {p.System}");
        if (p.DurationMinutes.HasValue) sb.AppendLine($"⏱ Длительность: {p.DurationMinutes / 60} ч");
        sb.AppendLine($"🔒 Видимость: {RenderVisibilityText(p.Visibility)}");
        sb.AppendLine();
        sb.AppendLine($"Слоты ({p.Pool?.Slots.Count ?? 0}):");
        if (p.Pool is not null)
        {
            foreach (var s in p.Pool.Slots)
            {
                sb.AppendLine($"  • {s.ScheduledAt.FormatMoscow()} — мест {s.MaxPlayers}, waitlist {(s.Waitlist ? "вкл" : "выкл")}");
            }
        }
        return (sb.ToString(), new InlineKeyboardMarkup(new[]
        {
            new[] { InlineKeyboardButton.WithCallbackData("✅ Создать пул", WizardCallbackData.Create()) },
            new[] { InlineKeyboardButton.WithCallbackData("⬅️ Назад",       WizardCallbackData.Back()) },
            new[] { InlineKeyboardButton.WithCallbackData("❌ Отмена",      WizardCallbackData.Cancel()) },
        }));
    }

    // ── Helpers ────────────────────────────────────────────────────────
    private static InlineKeyboardMarkup BackCancel() => new(new[]
    {
        new[] { InlineKeyboardButton.WithCallbackData("⬅️ Назад",  WizardCallbackData.Back()) },
        new[] { InlineKeyboardButton.WithCallbackData("❌ Отмена", WizardCallbackData.Cancel()) },
    });

    private static InlineKeyboardMarkup SkipBackCancel() => new(new[]
    {
        new[] { InlineKeyboardButton.WithCallbackData("⏭ Пропустить", WizardCallbackData.Choice("Skip", "1")) },
        new[] { InlineKeyboardButton.WithCallbackData("⬅️ Назад",     WizardCallbackData.Back()) },
        new[] { InlineKeyboardButton.WithCallbackData("❌ Отмена",    WizardCallbackData.Cancel()) },
    });

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

internal static class InlineKeyboardMarkupExtensions
{
    public static InlineKeyboardMarkup AppendBackCancel(this InlineKeyboardMarkup kb) => kb;
}
