import asyncio
import telebot
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
from g4f.client import Client
import time
import requests
from yandex_tts_free import YandexFreeTTS
import os
import shutil
import logging

# Настройка логирования
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Установка event loop policy
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

client_dict = {}


# Доступные модели
MODELS = ["blackbox", "claude-3-haiku", "nemotron-4-340b-instruct", "command-r+", "mixtral-8x7b", "Phi-3-mini-4k-instruct", "Nous-Hermes-2-Mixtral-8x7B-DPO", "CohereForAI/c4ai-command-r-plus", "databricks/dbrx-instruct", "deepseek-coder", "Qwen2-7B-Instruct", "SparkDesk-v1.1", "deepseek-chat", "meta/meta-llama-3-70b-instruct", "meta-llama/Meta-Llama-3-70B-Instruct", "meta-llama/Meta-Llama-3-8B-Instruct", "gpt-4o-mini", "llama-3-8b-instruct", "llama-3-70b-instruct", "llama-3-70b-chat", "llama-3-70b-instruct", "llama-3.1-70b-instruct", "llama-3.1-405b-instruct"]



# Доступные голоса
VOICES = ["oksana", "jane", "alyss", "omazh"]

# Define a name for the logger
logger_name = "my_bot_logger"

def create_model_selection_markup():
    markup = InlineKeyboardMarkup()
    for model in MODELS:
        markup.add(InlineKeyboardButton(model, callback_data=f"model_{model}"))
    return markup
    
def create_voice_selection_markup():
    markup = InlineKeyboardMarkup()
    for voice in VOICES:
        markup.add(InlineKeyboardButton(voice, callback_data=f"voice_{voice}"))
    return markup

def create_stop_ai_markup():
    markup = InlineKeyboardMarkup()
    markup.add(InlineKeyboardButton("🛑 Остановить ИИ", callback_data="stop_ai"))
    return markup

@bot.message_handler(commands=['ai'])
def send_welcome(message):
    bot.reply_to(message, "Привет! 👋 Выбери модель ИИ, с которой хочешь общаться:", reply_markup=create_model_selection_markup())
    if message.chat.id not in client_dict:
        client_dict[message.chat.id] = {'client': Client(), 'model': None, 'voice': 'oksana', 'ai_active': True}

client_dict = {}

@bot.callback_query_handler(func=lambda call: True)
def handle_callback_query(call):
    chat_id = call.message.chat.id
    data = call.data.split('_')
    
    if chat_id not in client_dict:
        client_dict[chat_id] = {'model': None, 'voice': None, 'ai_active': False}
    
    if data[0] == 'model':
        client_dict[chat_id]['model'] = data[1]
        bot.send_message(chat_id, f"Модель {data[1]} выбрана! 🤖 Теперь выбери голос для синтеза речи:", reply_markup=create_voice_selection_markup())
    elif data[0] == 'voice':
        client_dict[chat_id]['voice'] = data[1]
        bot.send_message(chat_id, f"Голос {data[1]} выбран! 🎙 Отправь сообщение, чтобы получить ответ от ИИ.")
    elif data[0] == 'stop_ai':
        client_dict[chat_id]['ai_active'] = False
        bot.send_message(chat_id, "ИИ остановлен. 🛑")

    return
    
@bot.message_handler(func=lambda message: True)
def handle_message(message):
    if message.chat.id not in client_dict or not client_dict[message.chat.id].get('ai_active', False):
        return
    
    client_info = client_dict[message.chat.id]
    client = client_info['client']
    model = client_info['model']
    voice = client_info['voice']
    
    start_time = time.time()
    bot.send_message(message.chat.id, "Генерирую ответ на ваш запрос… 🤔")
    
    response = None
    MAX_RETRIES = 3
    retries = 0
    while retries < MAX_RETRIES:
        try:
            response = client.chat.completions.create(
                model=model,
                messages=[{"role": "user", "content": message.text}],
            )
            break
        except requests.exceptions.ConnectionError:
            retries += 1
            logger.error(f"Ошибка соединения. Попытка {retries}/{MAX_RETRIES} 📡")
            time.sleep(5)  # Ждем 5 секунд перед следующей попыткой
        except Exception as e:
            logger.exception(f"Произошла ошибка: {str(e)}")
            bot.reply_to(message, "Извините, произошла ошибка при обработке вашего запроса. Попробуйте еще раз. 😓")
            return
    
    if response is None:
        bot.reply_to(message, "Не удалось получить ответ от модели после нескольких попыток. Пожалуйста, попробуйте позже. 😓")
        return
    
    end_time = time.time()
    execution_time = end_time - start_time
    output_text = response.choices[0].message.content
    
    # Оповещение пользователя о времени выполнения и модели
    bot.send_message(message.chat.id, f"Запрос занял {execution_time:.2f} секунд. Ответ предоставлен моделью {model}. ⏱")
    bot.reply_to(message, output_text, reply_markup=create_stop_ai_markup())
    
    # Генерация речи с выбранным голосом
    output_path = f'output{message.chat.id}'
    if not os.path.exists(output_path):
        os.makedirs(output_path)
    audio_file = os.path.join(output_path, 'output.mp3')
    
    tts = YandexFreeTTS()
    try:
        tts.generate_speech_ya(output_path, 'output.mp3', output_text, voice)
        
        # Отправка аудиофайла пользователю
        with open(audio_file, 'rb') as audio:
            bot.send_audio(message.chat.id, audio)
        
        # Удаление аудиофайла и папки после отправки
        shutil.rmtree(output_path)
    except Exception as e:
        logger.exception(f"Ошибка при генерации речи: {str(e)}")
        bot.reply_to(message, "Произошла ошибка при синтезе речи. Попробуйте еще раз. 😓")


Удаление сообщения после ответа от ИИ:
Генерирую ответ на ваш запрос… 🤔
Удаление сообщения выбора ии и голоса, возможность завершить диалог с ИИ под сообщениям с выводом ответа в виде инлайн кнопки(ПОСЛЕ ЗАВЕРЕШЕНИЕ ИИ НЕ БУДЕТ ОТВЕЧАТЬ, УБЕРИ НЕ РАБОЧУЮ КНОПКУ ОСТАНОВИТЬ)