не меняя код и логику работы добавь в него красоты чтобы пользователям было приятнее работать. import { Telegraf } from 'telegraf';
import LocalSession from 'telegraf-session-local';
import fetch from 'node-fetch';
import config from 'config';

const BOT_TOKEN = config.get('BOT_TOKEN');
const API_KEY = config.get('API_KEY');

const bot = new Telegraf(BOT_TOKEN);

// Настройка сессий
bot.use(new LocalSession({ database: 'sessions_db.json' }).middleware());

let trackingIntervals = {};

// Функция для получения списка складов
async function fetchWarehouses(apiKey) {
  try {
    const response = await fetch('https://supplies-api.wildberries.ru/api/v1/warehouses', {
      headers: {
        Authorization: `Bearer ${apiKey}`,
      },
    });

    if (!response.ok) {
      throw new Error(`Ошибка: ${response.status}`);
    }

    return await response.json();
  } catch (error) {
    console.error('Ошибка при получении списка складов:', error);
    return null;
  }
}

// Функция для получения коэффициентов приёмки
async function fetchAcceptanceCoefficients(apiKey, warehouseID) {
  try {
    const response = await fetch(
      `https://supplies-api.wildberries.ru/api/v1/acceptance/coefficients?warehouseIDs=${warehouseID}`,
      {
        headers: {
          Authorization: `Bearer ${apiKey}`,
        },
      },
    );

    if (!response.ok) {
      throw new Error(`Ошибка: ${response.status}`);
    }

    return await response.json();
  } catch (error) {
    console.error('Ошибка при получении коэффициентов приёмки:', error);
    return null;
  }
}

const boxTypeNames = {
  2: 'Короба',
  5: 'Монопаллеты',
  6: 'Суперсейф',
};

// Обработчик команды /start
bot.start(async (ctx) => {
  if (!ctx.session.apiKey) {
    ctx.reply('Пожалуйста, отправьте ваш API ключ.');
    return;
  }

  const warehouses = await fetchWarehouses(ctx.session.apiKey);

  if (!warehouses || warehouses.length === 0) {
    ctx.reply('Нет доступных складов.');
    return;
  }

  warehousesCache = warehouses;
  const message = await ctx.reply('Выберите склад:', {
    reply_markup: {
      inline_keyboard: warehouses.map((warehouse) => [
        { text: warehouse.name, callback_data: JSON.stringify({ warehouseID: warehouse.ID }) },
      ]),
    },
  });

  // Сохраняем идентификатор сообщения в контексте
  ctx.session.messageId = message.message_id;
});

// Обработчик для нажатий на кнопки
bot.on('callback_query', async (ctx) => {
  const { warehouseID, boxTypeID, monitor, continueSearch, changeWarehouse } = JSON.parse(
    ctx.callbackQuery.data,
  );

  if (warehouseID && !boxTypeID) {
    // Если выбран склад, предложить выбрать тип поставки
    ctx.answerCbQuery();
    await ctx.editMessageText('Выберите тип поставки:', {
      reply_markup: {
        inline_keyboard: Object.keys(boxTypeNames).map((typeID) => [
          {
            text: boxTypeNames[typeID],
            callback_data: JSON.stringify({ warehouseID, boxTypeID: parseInt(typeID) }),
          },
        ]),
      },
    });
    return;
  }

  if (monitor !== undefined) {
    // Если ответ на вопрос об отслеживании
    if (monitor) {
      await ctx.editMessageText('Выбран мониторинг. Мы начнем отслеживать.');
      startMonitoring(ctx, warehouseID, boxTypeID);
    } else {
      await ctx.editMessageText('Мониторинг не будет запущен.');
    }
    return;
  }

  if (continueSearch !== undefined) {
    // Если ответ на вопрос о продолжении поиска
    if (continueSearch) {
      await ctx.editMessageText('Продолжаем поиск...');
      startMonitoring(ctx, warehouseID, boxTypeID);
    } else {
      await ctx.editMessageText('Мониторинг остановлен.');
      stopMonitoring(ctx);
    }
    return;
  }

  if (changeWarehouse !== undefined) {
    // Если ответ на вопрос о смене склада
    const warehouses = await fetchWarehouses(ctx.session.apiKey);

    if (!warehouses || warehouses.length === 0) {
      await ctx.editMessageText('Нет доступных складов.');
      return;
    }

    warehousesCache = warehouses;
    await ctx.editMessageText('Выберите склад:', {
      reply_markup: {
        inline_keyboard: warehouses.map((warehouse) => [
          { text: warehouse.name, callback_data: JSON.stringify({ warehouseID: warehouse.ID }) },
        ]),
      },
    });
    return;
  }

  if (boxTypeID) {
    ctx.answerCbQuery();

    const coefficients = await fetchAcceptanceCoefficients(ctx.session.apiKey, warehouseID);

    if (!coefficients || coefficients.length === 0) {
      await ctx.editMessageText('На этом складе нет доступных коэффициентов для приёмки.');
      return;
    }

    const filteredCoefficients = coefficients.filter(
      (coeff) => coeff.coefficient !== -1 && coeff.boxTypeID === boxTypeID,
    );

    let replyMessage = 'Доступные поставки:\n';
    filteredCoefficients.forEach((coeff) => {
      const date = new Date(coeff.date).toLocaleDateString();
      let cost;
      if (coeff.coefficient === 0) {
        cost = 'Бесплатная приёмка';
      } else {
        cost = `Платная приёмка коэффициент ${coeff.coefficient}`;
      }
      replyMessage += `Дата: ${date}, ${cost}, Тип: ${coeff.boxTypeName}\n`;
    });

    if (filteredCoefficients.length === 0) {
      await ctx.editMessageText('Нет доступных поставок по выбранному типу.');
      await ctx.reply('Будем отслеживать?', {
        reply_markup: {
          inline_keyboard: [
            [
              {
                text: 'Да',
                callback_data: JSON.stringify({ warehouseID, boxTypeID, monitor: true }),
              },
              {
                text: 'Нет',
                callback_data: JSON.stringify({ warehouseID, boxTypeID, monitor: false }),
              },
            ],
          ],
        },
      });
    } else {
      await ctx.editMessageText(
        `Склад: ${getWarehouseNameById(warehouseID)}, Тип поставки: ${boxTypeNames[boxTypeID]}\n` +
          replyMessage,
        {
          reply_markup: {
            inline_keyboard: [
              [
                {
                  text: 'Искать другой город?',
                  callback_data: JSON.stringify({ warehouseID, boxTypeID, changeWarehouse: true }),
                },
                {
                  text: 'Закончить поиск',
                  callback_data: JSON.stringify({ warehouseID, boxTypeID, continueSearch: false }),
                },
              ],
            ],
          },
        },
      );
    }
  }
});

// Функция для мониторинга коэффициентов
async function startMonitoring(ctx, warehouseID, boxTypeID) {
  if (trackingIntervals[ctx.chat.id]) {
    clearInterval(trackingIntervals[ctx.chat.id]);
  }

  trackingIntervals[ctx.chat.id] = setInterval(async () => {
    const coefficients = await fetchAcceptanceCoefficients(ctx.session.apiKey, warehouseID);

    if (coefficients) {
      const filteredCoefficients = coefficients.filter(
        (coeff) => coeff.coefficient !== -1 && coeff.boxTypeID === boxTypeID,
      );

      if (filteredCoefficients.length > 0) {
        clearInterval(trackingIntervals[ctx.chat.id]);
        trackingIntervals[ctx.chat.id] = null;

        let replyMessage = 'Обнаружены доступные поставки:\n';
        filteredCoefficients.forEach((coeff) => {
          const date = new Date(coeff.date).toLocaleDateString();
          let cost;
          if (coeff.coefficient === 0) {
            cost = 'Бесплатная приёмка';
          } else {
            cost = `Платная приёмка коэффициент ${coeff.coefficient}`;
          }
          replyMessage += `Дата: ${date}, ${cost}, Тип: ${coeff.boxTypeName}\n`;
        });

        await ctx.reply(
          `Склад: ${getWarehouseNameById(warehouseID)}, Тип поставки: ${
            boxTypeNames[boxTypeID]
          }\n` + replyMessage,
          {
            reply_markup: {
              inline_keyboard: [
                [
                  {
                    text: 'Искать другой город?',
                    callback_data: JSON.stringify({
                      warehouseID,
                      boxTypeID,
                      changeWarehouse: true,
                    }),
                  },
                  {
                    text: 'Закончить поиск',
                    callback_data: JSON.stringify({
                      warehouseID,
                      boxTypeID,
                      continueSearch: false,
                    }),
                  },
                ],
              ],
            },
          },
        );
      }
    }
  }, 60000); // интервал 1 минута
}

// Функция для остановки мониторинга
function stopMonitoring(ctx) {
  if (trackingIntervals[ctx.chat.id]) {
    clearInterval(trackingIntervals[ctx.chat.id]);
    delete trackingIntervals[ctx.chat.id];
  }
}

// Команда /stop для остановки мониторинга
bot.command('stop', (ctx) => {
  stopMonitoring(ctx);
  ctx.reply('Мониторинг остановлен.');
});

// Команда /changeapi для смены API ключа
bot.command('changeapi', (ctx) => {
  ctx.reply('Пожалуйста, отправьте новый API ключ.');
});

// Обработчик для получения API ключа от пользователя
bot.on('text', (ctx) => {
  if (ctx.message.text.startsWith('/changeapi')) {
    return;
  }
  if (ctx.message.text.startsWith('/help')) {
    ctx.reply(
      'Доступные команды:\n' +
        '/start - Начать мониторинг\n' +
        '/stop - Остановить мониторинг\n' +
        '/changeapi - Сменить API ключ\n' +
        '/help - Показать справку\n\n' +
        'Как работать с ботом:\n' +
        '1. Нажмите /start для начала мониторинга.\n' +
        '2. Выберите представленный склад.\n' +
        '3. Выберите тип поставки.\n' +
        '4. Бот будет отслеживать доступные поставки и уведомлять вас о них.',
    );
    return;
  }
  ctx.session.apiKey = ctx.message.text;
  ctx.reply(
    'API ключ сохранен. Теперь вы можете использовать команду /start для начала мониторинга.',
  );
});

// Команда /help для отображения справки
bot.command('help', (ctx) => {
  ctx.reply(
    'Доступные команды:\n' +
      '/start - Начать мониторинг\n' +
      '/stop - Остановить мониторинг\n' +
      '/changeapi - Сменить API ключ\n' +
      '/help - Показать справку\n\n' +
      'Как работать с ботом:\n' +
      '1. Нажмите /start для начала мониторинга.\n' +
      '2. Выберите представленный склад.\n' +
      '3. Выберите тип поставки.\n' +
      '4. Бот будет отслеживать доступные поставки и уведомлять вас о них.',
  );
});

// Функция для получения имени склада по его ID
let warehousesCache = [];
function getWarehouseNameById(id) {
  const warehouse = warehousesCache.find((w) => w.ID === id);
  return warehouse ? warehouse.name : 'Неизвестный склад';
}

// Установка команд меню
bot.telegram.setMyCommands([
  { command: 'start', description: 'Начать мониторинг' },
  { command: 'stop', description: 'Остановить мониторинг' },
  { command: 'changeapi', description: 'Сменить API ключ' },
  { command: 'help', description: 'Показать справку' },
]);

bot.launch();
console.log('Бот запущен');

process.once('SIGINT', () => bot.stop('SIGINT'));
process.once('SIGTERM', () => bot.stop('SIGTERM'));