import os
import sys
import json
import threading
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import asyncio
import aiohttp
import socket

# Forzar IPv4 a nivel global para evitar problemas de conectividad en Docker/ZimaOS
orig_getaddrinfo = socket.getaddrinfo
def patched_getaddrinfo(*args, **kwargs):
    responses = orig_getaddrinfo(*args, **kwargs)
    return [res for res in responses if res[0] == socket.AF_INET]
socket.getaddrinfo = patched_getaddrinfo

from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Application, CommandHandler, MessageHandler, CallbackQueryHandler, ContextTypes, filters

from botdiscord.config import load_config, get_telegram_token, get_libretranslate_url
from botdiscord.database import (
    init_db as init_shared_db, 
    save_message, get_message, save_translation, get_cached_translation
)
from botdiscord.translate import load_lang_mappings, get_lang_mapping, get_flag_mapping, get_name_to_code

load_config()
from botdiscord.database import init_db
init_db()
load_lang_mappings("telegram")

PENDING_FILE = "/app/data/pending_translations.json"

def load_pending_translations():
    try:
        if os.path.exists(PENDING_FILE):
            with open(PENDING_FILE, "r") as f:
                return json.load(f)
    except:
        pass
    return {}

def save_pending_translations(data):
    try:
        with open(PENDING_FILE, "w") as f:
            json.dump(data, f)
    except:
        pass

user_languages = {}
pending_translations = load_pending_translations()

# Limitar el tamaño del diccionario para evitar fugas de memoria (mantener últimas 1000)
def cleanup_pending_translations():
    if len(pending_translations) > 1000:
        try:
            sorted_keys = sorted(pending_translations.keys(), key=lambda x: int(x))
            for k in sorted_keys[:-1000]:
                del pending_translations[k]
        except:
            keys = list(pending_translations.keys())
            for k in keys[:200]:
                del pending_translations[k]

lock = threading.Lock()

def get_lang_keyboard(bot_type="telegram"):
    lang_mapping = get_lang_mapping(bot_type)
    flag_mapping = get_flag_mapping(bot_type)
    
    buttons = []
    for code, name in lang_mapping.items():
        flag = flag_mapping.get(code, "")
        label = flag if flag else name
        buttons.append(InlineKeyboardButton(label, callback_data=f"trans_{code}"))
    
    # Agrupar en filas de 4 botones (columnas)
    keyboard = [buttons[i:i + 4] for i in range(0, len(buttons), 4)]
    return InlineKeyboardMarkup(keyboard)

async def translate_text_telegram(text: str, target_lang: str) -> str:
    # Usamos la función compartida de translate.py para tener segmentación y soporte multilingüe
    from botdiscord.translate import translate_text
    translated = await translate_text(text, target_lang)
    
    # Desescapamos el HTML para Telegram (evitar &quot; etc)
    import html
    return html.unescape(translated)

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    await update.message.reply_text(
        "¡Hola! Soy un bot de traducción.\n\n"
        "Envíame cualquier texto y lo traduciré al idioma que elijas.\n"
        "Usa /idiomas para seleccionar el idioma de traducción."
    )

async def languages_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
    lang_mapping = get_lang_mapping("telegram")
    flag_mapping = get_flag_mapping("telegram")
    
    buttons = []
    for code, name in lang_mapping.items():
        flag = flag_mapping.get(code, "")
        label = flag if flag else name
        buttons.append(InlineKeyboardButton(label, callback_data=f"lang_{code}"))
        
    keyboard = [buttons[i:i + 4] for i in range(0, len(buttons), 4)]
    reply_markup = InlineKeyboardMarkup(keyboard)
    
    await update.message.reply_text(
        "Selecciona el idioma de traducción:",
        reply_markup=reply_markup
    )

async def language_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    await query.answer()
    
    lang_code = query.data.replace("lang_", "")
    lang_mapping = get_lang_mapping("telegram")
    flag_mapping = get_flag_mapping("telegram")
    
    lang_name = "Desconocido"
    for name, code in lang_mapping.items():
        if code == lang_code:
            lang_name = name
            break
            
    lang_flag = flag_mapping.get(lang_code, "")
    user_languages[query.from_user.id] = lang_code
    
    display_name = f"{lang_flag} {lang_name}" if lang_flag else lang_name
    await query.edit_message_text(f"Idioma predeterminado configurado: {display_name}")

async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
    text = update.message.text.strip()
    if len(text) < 2: return
    
    reply_markup = get_lang_keyboard()
    sent_message = await update.message.reply_text(
        f"🌍 *Original:*\n{text}",
        parse_mode="Markdown",
        reply_markup=reply_markup
    )
    
    # Guardamos en MySQL en lugar del JSON local
    save_message(sent_message.message_id, update.effective_chat.id, update.effective_user.id, text, {}, 'telegram')

async def handle_photo(update: Update, context: ContextTypes.DEFAULT_TYPE):
    caption = update.message.caption
    if not caption: return
    
    reply_markup = get_lang_keyboard()
    sent_message = await update.message.reply_photo(
        update.message.photo[-1].file_id,
        caption=f"🌍 *Original:*\n{caption}",
        parse_mode="Markdown",
        reply_markup=reply_markup
    )
    # Guardamos en MySQL
    save_message(sent_message.message_id, update.effective_chat.id, update.effective_user.id, caption, {}, 'telegram')

async def translation_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    await query.answer()
    
    lang_code = query.data.replace("trans_", "")
    message_id = query.message.message_id
    
    # Intentamos obtener del caché de traducciones primero
    cached = get_cached_translation(message_id, lang_code)
    
    # Recuperamos el mensaje original de MySQL
    db_msg = get_message(message_id)
    
    if not db_msg:
        await query.message.reply_text("⚠️ No se encontró el texto original en la base de datos.")
        return
    
    text = db_msg['content']
    
    if cached:
        translated = cached
    else:
        # Traducimos usando la lógica compartida
        from botdiscord.translate import translate_text
        translated = await translate_text(text, lang_code)
        # Guardamos en caché MySQL
        save_translation(message_id, lang_code, translated)
    
    # Desescapamos el HTML para Telegram
    import html
    translated = html.unescape(translated)
    
    lang_mapping = get_lang_mapping("telegram")
    flag_mapping = get_flag_mapping("telegram")
    
    lang_name = "Desconocido"
    for name, code in lang_mapping.items():
        if code == lang_code:
            lang_name = name
            break
            
    lang_flag = flag_mapping.get(lang_code, "")
    display_name = f"{lang_flag} {lang_name}" if lang_flag else lang_name
    
    reply_markup = get_lang_keyboard()
    new_text = f"{translated}\n\n📝 *Original:*\n{text}"
    
    try:
        if query.message.caption:
            await query.edit_message_caption(
                caption=new_text,
                parse_mode="Markdown",
                reply_markup=reply_markup
            )
        else:
            await query.edit_message_text(
                text=new_text,
                parse_mode="Markdown",
                reply_markup=reply_markup
            )
    except Exception as e:
        pass

async def handle_document(update: Update, context: ContextTypes.DEFAULT_TYPE):
    caption = update.message.caption
    if not caption: return
    reply_markup = get_lang_keyboard()
    sent_message = await update.message.reply_document(
        update.message.document.file_id,
        caption=f"🌍 *Original:*\n{caption}",
        parse_mode="Markdown",
        reply_markup=reply_markup
    )
    pending_translations[str(sent_message.message_id)] = caption

async def handle_video(update: Update, context: ContextTypes.DEFAULT_TYPE):
    caption = update.message.caption
    if not caption: return
    reply_markup = get_lang_keyboard()
    sent_message = await update.message.reply_video(
        update.message.video.file_id,
        caption=f"🌍 *Original:*\n{caption}",
        parse_mode="Markdown",
        reply_markup=reply_markup
    )
    pending_translations[str(sent_message.message_id)] = caption

async def handle_animation(update: Update, context: ContextTypes.DEFAULT_TYPE):
    caption = update.message.caption
    if not caption: return
    reply_markup = get_lang_keyboard()
    sent_message = await update.message.reply_animation(
        update.message.animation.file_id,
        caption=f"🌍 *Original:*\n{caption}",
        parse_mode="Markdown",
        reply_markup=reply_markup
    )
    pending_translations[str(sent_message.message_id)] = caption

async def handle_audio(update: Update, context: ContextTypes.DEFAULT_TYPE):
    caption = update.message.caption
    if not caption: return
    reply_markup = get_lang_keyboard()
    sent_message = await update.message.reply_audio(
        update.message.audio.file_id,
        caption=f"🌍 *Original:*\n{caption}",
        parse_mode="Markdown",
        reply_markup=reply_markup
    )
    pending_translations[str(sent_message.message_id)] = caption

async def handle_voice(update: Update, context: ContextTypes.DEFAULT_TYPE):
    caption = update.message.caption
    if not caption: return
    reply_markup = get_lang_keyboard()
    sent_message = await update.message.reply_voice(
        update.message.voice.file_id,
        caption=f"🌍 *Original:*\n{caption}",
        parse_mode="Markdown",
        reply_markup=reply_markup
    )
    pending_translations[str(sent_message.message_id)] = caption


async def handle_sticker(update: Update, context: ContextTypes.DEFAULT_TYPE):
    return

async def handle_video_note(update: Update, context: ContextTypes.DEFAULT_TYPE):
    return

def run_telegram_bot():
    try:
        from botdiscord.database import init_db
        init_db()
    except Exception as e:
        print(f"⚠️ Advertencia: Error al inicializar DB (reintentando luego): {e}")
    
    token = get_telegram_token()
    if not token or token == "TU_TELEGRAM_BOT_TOKEN":
        print("ERROR: Configura el token de Telegram en config.yaml o .env")
        return
    
    # Configuración de red de máxima compatibilidad (Forzar IPv4 y HTTP/1.1)
    from telegram.request import HTTPXRequest
    import httpx
    import socket

    # Creamos un pool que ignore IPv6 si es posible
    limits = httpx.Limits(max_connections=10, max_keepalive_connections=5)
    
    request = HTTPXRequest(
        connect_timeout=30.0,
        read_timeout=30.0,
        write_timeout=30.0,
        pool_timeout=30.0,
        http_version="1.1"
    )
    
    application = Application.builder().token(token).request(request).build()
    
    application.add_handler(CommandHandler("start", start))
    application.add_handler(CommandHandler("idiomas", languages_command))
    application.add_handler(CallbackQueryHandler(translation_callback, pattern="^trans_"))
    application.add_handler(MessageHandler(filters.PHOTO, handle_photo))
    application.add_handler(MessageHandler(filters.Document.ALL, handle_document))
    application.add_handler(MessageHandler(filters.VIDEO, handle_video))
    application.add_handler(MessageHandler(filters.ANIMATION, handle_animation))
    application.add_handler(MessageHandler(filters.AUDIO, handle_audio))
    application.add_handler(MessageHandler(filters.VOICE, handle_voice))
    application.add_handler(MessageHandler(filters.Sticker.ALL, handle_sticker))
    application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_message))
    
    print("Bot Telegram iniciado. Presiona Ctrl+C para detener.")
    application.run_polling(allowed_updates=Update.ALL_TYPES)

if __name__ == "__main__":
    run_telegram_bot()
