using System.Text;
using AiLogia.Bot.Core;
using AiLogia.Bot.Data;
using AiLogia.Bot.Diagnostics;
using AiLogia.Bot.Models;
using AiLogia.Bot.Services;
using AiLogia.Bot.Utils;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Telegram.Bot;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using Telegram.Bot.Types.ReplyMarkups;

namespace AiLogia.Bot.Handlers;

public class QuestionFlowHandler(
    IConfiguration config,
    ITelegramBotClient bot,
    ISystemLogService log,
    IUserActionTracker tracker,
    ITestsRepository repo,
    IServiceProvider sp) : ICallbackHandler
{
    private readonly string _botUsername = config.GetValue<string>("BotTgName") ?? "";

    public bool CanHandle(string data) =>
        data.StartsWith("start:") || data.StartsWith("answer:") || data.StartsWith("back:");

    public async Task HandleAsync(CallbackQuery callback)
    {
        await tracker.TrackCallbackAsync("callback:question_flow", callback);

        if (callback.Data is null) return;

        if (callback.Data.StartsWith("start:"))
            await HandleStartAsync(callback);
        else if (callback.Data.StartsWith("answer:"))
            await HandleAnswerAsync(callback);
        else if (callback.Data.StartsWith("back:"))
            await HandleBackAsync(callback);
    }

    private async Task HandleStartAsync(CallbackQuery callback)
    {
        if (!int.TryParse(callback.Data.Split(':')[1], out var testId)) return;

        var test = await repo.GetTestByIdAsync(testId);
        var question = await repo.GetFirstQuestionAsync(testId);
        var total = await repo.GetTotalQuestionsCountAsync(testId);

        await ShowQuestionAsync(callback, test, question, total, false);
    }

    private async Task HandleAnswerAsync(CallbackQuery callback)
    {
        var parts = callback.Data.Split(':');
        if (parts.Length != 4 ||
            !int.TryParse(parts[1], out var testId) ||
            !int.TryParse(parts[2], out var questionId) ||
            !int.TryParse(parts[3], out var answerId))
        {
            await bot.SendMessage(callback.From.Id, "❌ Ошибка разбора ответа.");
            return;
        }

        var userId = callback.From.Id;
        var username = callback.From.Username;

        var test = await repo.GetTestByIdAsync(testId);
        if (test == null)
        {
            await bot.SendMessage(userId, "❌ Тест не найден.");
            return;
        }

        await repo.SaveUserAnswerAsync(userId, testId, questionId, answerId);

        var next = await repo.GetNextQuestionAsync(testId, questionId);
        if (next != null)
        {
            var total = await repo.GetTotalQuestionsCountAsync(testId);
            var hasPrev = await repo.GetPreviousQuestionAsync(testId, next.Id) != null;
            await ShowQuestionAsync(callback, test, next, total, hasPrev);
        }
        else
        {
            // Удаляем сообщение с последним вопросом
            if (callback.Message?.MessageId is int mid)
            {
                try { await bot.DeleteMessage(callback.Message.Chat.Id, mid); }
                catch { /* ignore */ }
            }

            await ShowResultAsync(callback, test, userId, username);
        }
    }

    private async Task HandleBackAsync(CallbackQuery callback)
    {
        var parts = callback.Data.Split(':');
        if (parts.Length != 3 ||
            !int.TryParse(parts[1], out var testId) ||
            !int.TryParse(parts[2], out var currentQuestionId))
        {
            await bot.SendMessage(callback.From.Id, "❌ Неверный формат команды Назад.");
            return;
        }

        var prev = await repo.GetPreviousQuestionAsync(testId, currentQuestionId);
        if (prev != null)
        {
            var test = await repo.GetTestByIdAsync(testId);
            var total = await repo.GetTotalQuestionsCountAsync(testId);
            var hasEarlier = await repo.GetPreviousQuestionAsync(testId, prev.Id) != null;

            await ShowQuestionAsync(callback, test, prev, total, hasEarlier);
        }
        else
        {
            // Возврат на первый вопрос через RouteCallback внутри
            var router = sp.GetRequiredService<ICommandsRouter>();
            var fake = new CallbackQuery
            {
                From = callback.From,
                Data = $"start:{testId}",
                Message = callback.Message
            };
            await router.RouteCallbackAsync(fake);
        }
    }

    private async Task ShowQuestionAsync(
        CallbackQuery callback,
        TestModel test,
        QuestionModel question,
        int total,
        bool allowBack)
    {
        if (callback.Message?.MessageId is int mid)
        {
            try
            {
                await bot.DeleteMessage(callback.Message.Chat.Id, mid);
            }
            catch { /* ignore */ }
        }

        var index = await repo.GetQuestionOrderIndexAsync(question.Id);
        var sb = new StringBuilder();

        sb.AppendLine($"🧪 {test.Title}");
        sb.AppendLine();
        sb.AppendLine($"❓ *{index} / {total}:*  {question.Text}");
        sb.AppendLine();

        foreach (var ans in question.Answers)
            sb.AppendLine($"{ans.Letter}) {ans.Text}");

        var buttons = question.Answers
      .Select(a => InlineKeyboardButton.WithCallbackData(a.Letter, $"answer:{test.Id}:{question.Id}:{a.Id}"))
      .ToList();

        // Формируем ряды кнопок по 4 в строке
        var rows = buttons.Chunk(4).Select(chunk => chunk.ToArray()).ToList();

        if (allowBack)
        {
            // Кнопка «⬅️ Предыдущий вопрос» всегда отдельной строкой
            rows.Add(new[] { InlineKeyboardButton.WithCallbackData("⬅️ Предыдущий вопрос", $"back:{test.Id}:{question.Id}") });
        }

        var markup = new InlineKeyboardMarkup(rows);

        await bot.SendMessage(
            chatId: callback.From.Id,
            text: sb.ToString(),
            parseMode: ParseMode.Markdown,
            replyMarkup: markup
        );
    }

    private async Task ShowResultAsync(CallbackQuery callback, TestModel test, long userId, string username)
    {
        var (result, interpretation) = await repo.CalculateResultAsync(test.Id, userId, test.ResultFunctionName);
        await repo.SaveUserResultAsync(userId, test.Id, result, interpretation, null);
        await repo.ClearUserProgressAsync(userId, test.Id);

        var model = new TestResultModel
        {
            TestId = test.Id,
            TestTitle = test.Title,
            ResultText = result,
            Interpretation = interpretation,
            CompletedAt = DateTime.UtcNow,
            TestAccessMode = test.AccessMode,
            BotUsername = _botUsername
        };

        /*

                if (test.AccessMode == "channel_subscription_required")
                {
                    var isSub = await cache.GetAsync(userId, username, false);
                    if (!isSub)
                    {
                        var channels = await promo.GetActiveChannelsAsync();
                        if (channels.Any())
                        {
                            var text = new StringBuilder();
                            text.AppendLine("🔒 Результаты доступны только подписчикам:");
                            foreach (var ch in channels)
                                text.AppendLine($"🔗 [{ch.Name}]({ch.Url})");

                            await bot.SendMessage(userId, text.ToString(), ParseMode.Markdown);
                            SubscriptionFollowUpMonitor.AddPending(userId, username, model, PendingSubscriptionResult.PendingTestResults);
                            return;
                        }
                    }
                }
                else if (test.AccessMode == "payed_subscription_required")
                {
                    var access = await repo.GetOrCreateUserAccessAsync(userId);
                    if (access.AccessLevel != "paid" || (access.SubscriptionExpiresAt is not null && access.SubscriptionExpiresAt < DateTime.UtcNow))
                    {
                        await bot.SendMessage(userId, "🔒 Этот тест доступен только по платной подписке.\n\nОформите подписку: /pay", ParseMode.Markdown);
                        return;
                    }
                }
        */

        foreach (var chunk in TelegramMessageHelper.FormatResultsMessageFromModel(model))
            await bot.SendMessage(userId, chunk, ParseMode.Markdown);

        await bot.SendMessage(userId,
            @"Что дальше?

💡 /recommendations — получить персональные рекомендации по саморазвитию
📋 /tests — пройти следующий тест
🧠 /me — все ваши результаты
            
👉 Узнайте больше о том какие навыки можно развить в себе прямо сейчас на сайте AILogia.ru",
            ParseMode.Markdown);
    }
}
