import { Telegraf, session } from 'telegraf';
import { message } from 'telegraf/filters';
import { code } from 'telegraf/format';
import config from 'config';
import { ogg } from './src/ogg.js';
import { transcribeAudio, initializeVosk } from './src/transcriber.js';
import { Client } from '@gradio/client';

process.on('uncaughtException', (err) => {
  console.error('Uncaught Exception:', err);
});

process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled Rejection at:', promise, 'reason:', reason);
});

const INITIAL_SESSION = {
  messages: [],
};

const BOT_TOKEN = config.get('TELEGRAM_TOKEN');
const bot = new Telegraf(BOT_TOKEN);

let gradioClient;
let voskReady = false;

async function initGradioClient() {
  try {
    const client = await Client.connect('yuntian-deng/ChatGPT4');
    console.log('Gradio client initialized');
    return client;
  } catch (error) {
    console.error('Ошибка подключения клиента Gradio:', error);
    throw error;
  }
}

async function getPrediction(app, inputText, apiEndpoint) {
  const parameters = {
    inputs: inputText,
    top_p: 1.0,
    temperature: 1.0,
    chat_counter: 0,
    chatbot: [],
  };

  try {
    // console.log(`Отправка на ${apiEndpoint}:`, parameters);

    const predictionResult = await app.predict(apiEndpoint, [
      parameters.inputs,
      parameters.top_p,
      parameters.temperature,
      parameters.chat_counter,
      parameters.chatbot,
    ]);

    const nestedArray = predictionResult.data[0];

    if (Array.isArray(nestedArray) && nestedArray.length > 0) {
      const lastPair = nestedArray[nestedArray.length - 1];
      if (Array.isArray(lastPair) && lastPair.length > 1) {
        const actualResponse = lastPair[1];
        if (typeof actualResponse === 'string') {
          return actualResponse;
        }
      }
    }

    console.warn('Получен неожиданный формат данных.');
    return 'Получен неожиданный формат данных.';
  } catch (error) {
    console.error(`Ошибка во время запроса ${apiEndpoint}:`, error);
    return 'Извините, произошла ошибка при обработке вашего запроса.';
  }
}

// Инициализация клиента Gradio
initGradioClient()
  .then((client) => {
    gradioClient = client;
    console.log('Gradio client successfully initialized. Launching bot...');
  })
  .catch((error) => {
    console.error('Не удалось инициализировать клиент Gradio:', error);
  });

// Асинхронная инициализация Vosk
(async () => {
  try {
    await initializeVosk();
    voskReady = true;
    console.log('Vosk model initialized');
  } catch (error) {
    console.error('Ошибка инициализации Vosk:', error);
  }
})();

bot.use(session());

bot.command('start', async (ctx) => {
  ctx.session = INITIAL_SESSION;
  await ctx.reply('Жду вашего голосового или текстового сообщения');
});

bot.on(message('voice'), async (ctx) => {
  ctx.session ??= INITIAL_SESSION;

  if (!voskReady) {
    await ctx.reply('Голосовая обработка ещё не готова. Попробуйте позже.');
    return;
  }

  try {
    const link = await ctx.telegram.getFileLink(ctx.message.voice.file_id);
    const userId = String(ctx.message.from.id);
    const oggPath = await ogg.create(link.href, userId);
    const mp3Path = await ogg.toMp3(oggPath, userId);
    const name = ctx.from.first_name;

    const text = await transcribeAudio(mp3Path);
    // console.log('Transcription text:', text); // Логирование результата транскрипции

    if (text && gradioClient) {
      // Убедимся, что текст получен и клиент инициализирован
      await ctx.reply(code(`${name}, я понял ваше сообщение: ${text}`));

      try {
        const responseMessage = await getPrediction(gradioClient, text, '/predict');
        console.log('Gradio response:', responseMessage); // Логирование ответа Gradio
        await ctx.reply(`${name}, ${responseMessage}`);
      } catch (error) {
        console.log('Error during prediction request:', error.message);
        await ctx.reply('Извините, произошла ошибка при обработке вашего запроса.');
      }
    } else {
      await ctx.reply('Извините, не удалось распознать ваш голос.');
    }
  } catch (error) {
    console.log('Ошибка при обработке голосового сообщения:', error.message);
    await ctx.reply('Произошла ошибка при обработке голосового сообщения.');
  }
});

bot.on(message('text'), async (ctx) => {
  ctx.session ??= INITIAL_SESSION;
  const text = ctx.message.text;

  if (text.includes('Кеша') && gradioClient) {
    const textAsked = text.slice(5);
    try {
      await ctx.reply(code('Сообщение принял. Жду ответ от сервера...'));

      const responseMessage = await getPrediction(gradioClient, textAsked, '/predict');
      // console.log(responseMessage);
      const name = ctx.from.first_name;
      await ctx.reply(`${name}, ${responseMessage}`);
    } catch (err) {
      console.log('Ошибка при обработке текстового сообщения:', err.message);
      const name = ctx.from.first_name;
      ctx.reply(
        `${name}, "Извините. Но из-за высокой нагрузки на сервер, я не смогу ответить Вам".`,
      );
    }
  }
});

bot.launch();

process.once('SIGINT', () => bot.stop('SIGINT'));
process.once('SIGTERM', () => bot.stop('SIGTERM'));
когда бот был выключен, после включение он увидел что его спрашивали и начал много сообщений повторять одних и тех же, нужно это исправить, нужно чтобы в коде проверялось, если его текстом или голосом спрашивали , то он должен давать только один раз ответ, не нужно повторения