using System;
using System.Collections.Generic;
using System.Text;
using GmRelay.Shared.Domain;

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

/// <summary>
/// Produces a (text, list of <see cref="WizardAction"/>s) pair for each
/// wizard step. This is the "view builder" half of ADR-002: the same
/// builder is used by every platform messenger, and each messenger is
/// responsible for converting the action list into its native UI
/// (Telegram's <c>InlineKeyboardMarkup</c> today, Discord components
/// later).
/// </summary>
public static class WizardStepViewBuilder
{
    public static (string Text, IReadOnlyList<WizardAction> Actions) Build(
        WizardDraft draft,
        WizardPayload payload,
        IReadOnlyList<WizardClubOption>? clubs = null)
    {
        return draft.Step switch
        {
            WizardStepNames.Type => BuildType(),
            WizardStepNames.Title => BuildTitle(),
            WizardStepNames.Description => BuildDescription(),
            WizardStepNames.Cover => BuildCover(),
            WizardStepNames.System => BuildSystem(),
            WizardStepNames.Duration => BuildDuration(),
            WizardStepNames.DateTime => BuildDateTime(),
            WizardStepNames.Capacity => BuildCapacity(),
            WizardStepNames.Visibility => BuildVisibility(),
            WizardStepNames.PickClub => BuildPickClub(clubs ?? Array.Empty<WizardClubOption>()),
            WizardStepNames.Publish => BuildPublish(),
            WizardStepNames.Confirm => BuildSingleConfirm(payload),

            WizardStepNames.PoolSystemDuration => BuildPoolSystemDuration(),
            WizardStepNames.PoolAddSlots => BuildPoolAddSlots(payload),
            WizardStepNames.PoolSlotDateTime => BuildPoolSlotDateTime(),
            WizardStepNames.PoolSlotCapacity => BuildPoolSlotCapacity(),
            WizardStepNames.PoolConfirm => BuildPoolConfirm(payload),

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

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

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

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

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

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

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

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

    private static (string, IReadOnlyList<WizardAction>) BuildCapacity() => (
        "👥 Введите лимит мест (1..50) одним числом.\nЗатем нажмите кнопку waitlist. Или сразу «♾ Без лимита».",
        new List<WizardAction>
        {
            new("✅ Waitlist вкл", WizardCallbackData.Choice(WizardStepNames.Capacity, "waitlist:on"), WizardActionStyle.Success),
            new("❌ Без waitlist", WizardCallbackData.Choice(WizardStepNames.Capacity, "waitlist:off"), WizardActionStyle.Danger),
            new("♾ Без лимита", WizardCallbackData.Choice(WizardStepNames.Capacity, "no_limit"), WizardActionStyle.Primary),
        });

    private static (string, IReadOnlyList<WizardAction>) BuildVisibility() => (
        "🔒 Выберите видимость.",
        new List<WizardAction>
        {
            new("🌐 Публичная в общем showcase", WizardCallbackData.Choice(WizardStepNames.Visibility, "public"), WizardActionStyle.Primary),
            new("🏠 Публичная в витрине клуба", WizardCallbackData.Choice(WizardStepNames.Visibility, "club"), WizardActionStyle.Primary),
            new("🔐 Только для членов клуба",   WizardCallbackData.Choice(WizardStepNames.Visibility, "members")),
            new("🏷 Выбрать клуб…",             WizardCallbackData.Choice(WizardStepNames.Visibility, "pickclub")),
        });

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

    private static (string, IReadOnlyList<WizardAction>) BuildPublish() => (
        "✨ Опубликовать в витрине сейчас?",
        new List<WizardAction>
        {
            new("✅ Опубликовать",  WizardCallbackData.Choice(WizardStepNames.Publish, "yes"), WizardActionStyle.Success),
            new("📝 Только в чате", WizardCallbackData.Choice(WizardStepNames.Publish, "no")),
        });

    private static (string, IReadOnlyList<WizardAction>) BuildSingleConfirm(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 List<WizardAction>
            {
                new("✅ Создать", WizardCallbackData.Create(), WizardActionStyle.Success),
                new("⬅️ Назад",   WizardCallbackData.Back()),
                new("❌ Отмена",  WizardCallbackData.Cancel(), WizardActionStyle.Danger),
            });
    }

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

    private static (string, IReadOnlyList<WizardAction>) BuildPoolAddSlots(WizardPayload p) => (
        $"📅 Слоты пула «{p.Title}»\n\nДобавлено: {(p.Pool?.Slots.Count ?? 0)}",
        new List<WizardAction>
        {
            new("➕ Добавить слот",      WizardCallbackData.Choice(WizardStepNames.PoolAddSlots, "add"), WizardActionStyle.Primary),
            new("✅ Готово, к превью",  WizardCallbackData.Choice(WizardStepNames.PoolAddSlots, "done"), WizardActionStyle.Success),
        });

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

    private static (string, IReadOnlyList<WizardAction>) BuildPoolSlotCapacity() => (
        "👥 Введите лимит мест (1..50) и выберите waitlist.",
        new List<WizardAction>
        {
            new("✅ Waitlist вкл",  WizardCallbackData.Choice(WizardStepNames.PoolSlotCapacity, "waitlist:on"), WizardActionStyle.Success),
            new("❌ Без waitlist",  WizardCallbackData.Choice(WizardStepNames.PoolSlotCapacity, "waitlist:off"), WizardActionStyle.Danger),
        });

    private static (string, IReadOnlyList<WizardAction>) BuildPoolConfirm(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 List<WizardAction>
            {
                new("✅ Создать пул", WizardCallbackData.Create(), WizardActionStyle.Success),
                new("⬅️ Назад",       WizardCallbackData.Back()),
                new("❌ Отмена",      WizardCallbackData.Cancel(), WizardActionStyle.Danger),
            });
    }

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

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

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