import { MyContext } from "../../types/myContext";
import { Conversation } from "@grammyjs/conversations";

// Тип разговора
type MyConversation = Conversation<MyContext>;

interface Action {
  readonly action: string;
  readonly label: string;
}

/**
 * Обработчик выбора нескольких действий
 * @param conversation - Инстанс Conversation
 * @param ctx - Контекст
 * @param availableActions - Список доступных действий
 * @returns Список выбранных действий
 */
export async function selectMultipleActions<T extends readonly Action[]>(
  conversation: MyConversation,
  ctx: MyContext,
  availableActions: T,
): Promise<T[number]["action"][]> {
  try {
    if (!Array.isArray(availableActions) || availableActions.length === 0) {
      throw new Error("Список доступных действий пуст или не определён.");
    }

    const selectedActions = new Set<T[number]["action"]>();

    const updateKeyboard = () => {
      return availableActions.map(({ action, label }) => [
        {
          text: `${selectedActions.has(action) ? " ✅️ " : ""}${label}`,
          callback_data: `action:${action}`,
        },
      ]);
    };

    // Отправляем начальное сообщение
    await ctx.reply(
      "Выберите одно или несколько действий, которые будут доступны при сканировании этого QR-кода. Нажмите «Готово», когда закончите выбор:",
      {
        reply_markup: {
          inline_keyboard: [
            ...updateKeyboard(),
            [{ text: "Готово", callback_data: "action:done" }],
          ],
        },
      },
    );

    while (true) {
      let actionChoice;
      try {
        actionChoice = await conversation.waitFor("callback_query:data");
      } catch (err) {
        console.error("Ошибка ожидания callback_query:", err);
        await ctx.reply(
          "Произошла ошибка при ожидании вашего выбора. Попробуйте снова.",
        );
        continue;
      }

      const choice = actionChoice.update.callback_query?.data;

      if (!choice || !choice.startsWith("action:")) {
        // Игнорируем callback_data, которые не относятся к текущему этапу
        console.warn(`Игнорируем callback_data: ${choice}`);
        await actionChoice.answerCallbackQuery({
          text: "Неизвестное действие.",
        });
        continue;
      }

      const action = choice.replace("action:", "");

      if (action === "done") {
        await actionChoice.answerCallbackQuery({
          text: "Выбор действий завершён!",
        });

        break;
      }

      // Проверка: является ли выбор валидным
      const validChoice = availableActions.find((a) => a.action === action);
      if (!validChoice) {
        console.error(`Недопустимое действие: ${action}`);
        await actionChoice.answerCallbackQuery({
          text: "Неверный выбор. Попробуйте снова.",
        });
        continue;
      }

      // Добавляем или убираем действие
      if (selectedActions.has(action as T[number]["action"])) {
        selectedActions.delete(action as T[number]["action"]);
      } else {
        selectedActions.add(action as T[number]["action"]);
      }

      await actionChoice.answerCallbackQuery({
        text: `Вы ${
          selectedActions.has(action as T[number]["action"])
            ? "добавили"
            : "убрали"
        } действие.`,
      });

      // Перерисовываем клавиатуру
      try {
        await actionChoice.editMessageReplyMarkup({
          reply_markup: {
            inline_keyboard: [
              ...updateKeyboard(),
              [{ text: "Готово", callback_data: "action:done" }],
            ],
          },
        });
      } catch (err) {
        console.error("Ошибка обновления клавиатуры:", err);
        await ctx.reply(
          "Произошла ошибка при обновлении выбора. Попробуйте снова.",
        );
      }
    }

    return Array.from(selectedActions);
  } catch (err) {
    console.error("Общая ошибка в selectMultipleActions:", err);
    await ctx.reply(
      "Произошла непредвиденная ошибка. Попробуйте снова или обратитесь в поддержку.",
    );
    return [];
  }
}
