# -*- coding: utf-8 -*-
import os
import re
import json
import logging
from dataclasses import dataclass
from typing import Dict, Pattern, List
from pathlib import Path

from dotenv import load_dotenv
from telegram import Update, InlineKeyboardMarkup, InlineKeyboardButton
from telegram.ext import (
    ApplicationBuilder, ContextTypes,
    CommandHandler, MessageHandler, CallbackQueryHandler,
    filters
)

# -------------------- Carga de configuración e idiomas --------------------
load_dotenv()
TOKEN = os.getenv("TELEGRAM_TOKEN")

DATA_DIR = Path(__file__).parent / "data"

DEFAULT_CONFIG = {
    "website_url": "https://www.newintlcenter.org",
    "map_url": "https://www.google.com/maps?q=80+Maiden+Lane+13th+Floor+New+York+NY+10028",
    "default_lang": "es"
}

@dataclass
class Matcher:
    pattern: Pattern
    answer: str

I18N: Dict[str, dict] = {}
LANGS: Dict[str, str] = {}   # code -> display name
MATCHERS: Dict[str, List[Matcher]] = {}
CONFIG: Dict[str, str] = DEFAULT_CONFIG.copy()

# ---------- Helper: texto al pie (Opción 2, ultra-explícito) ----------
HINT_TEXT = "💡 Escribe /menu para ver opciones y /lang para cambiar idioma."
def with_hint(s: str) -> str:
    return f"{s}\n\n{HINT_TEXT}"

# ------------------------------ Utilidades JSON ------------------------------
def _load_json(path: Path) -> dict:
    with path.open("r", encoding="utf-8") as f:
        return json.load(f)

def load_config() -> Dict[str, str]:
    cfg_path = DATA_DIR / "config.json"
    cfg = DEFAULT_CONFIG.copy()
    if cfg_path.exists():
        try:
            cfg.update(_load_json(cfg_path))
        except Exception as e:
            logging.warning(f"No se pudo leer config.json: {e}")
    return cfg

def discover_languages() -> Dict[str, dict]:
    """
    Busca archivos data/i18n_*.json y devuelve:
    { "es": {"name": "Español", "i18n": {...}}, ... }
    """
    langs = {}
    DATA_DIR.mkdir(parents=True, exist_ok=True)
    for p in DATA_DIR.glob("i18n_*.json"):
        code = p.stem.split("_", 1)[1]
        try:
            i18n = _load_json(p)
            name = i18n.get("name", code)
            langs[code] = {"name": name, "i18n": i18n}
        except Exception as e:
            logging.warning(f"No se pudo cargar {p.name}: {e}")
    return langs

def load_faq(lang: str) -> Dict[str, str]:
    """
    Carga data/faq_<lang>.json si existe; si no, arma un fallback simple.
    Usa placeholders: {WEBSITE_URL}, {MAP_URL}, {ADDRESS}, {MAP_LABEL}, {PROGRAMS}
    """
    path = DATA_DIR / f"faq_{lang}.json"
    if path.exists():
        try:
            return _load_json(path)
        except Exception as e:
            logging.warning(f"No se pudo leer {path.name}: {e}")

    # Fallback mínimo (usa textos base del i18n correspondiente)
    i18n = I18N.get(lang, {})
    website = CONFIG["website_url"]
    address = i18n.get("address", "80 Maiden Lane, 13th Floor, New York, NY 10028")
    map_label = i18n.get("open_map_label", "🗺️ Map")

    return {
        ("horario|horarios|schedule" if lang != "en" else "schedule|time|when"):
            i18n.get("schedule_text", f"🗓️ Schedules change. See: {website}"),

        ("direcci[oó]n|ubicaci[oó]n|address|location" if lang == "es" else
         "adresse|localisation|address|location" if lang == "fr" else
         "location|address|where"):
            f"📍 {{ADDRESS}}\n{map_label}: {{MAP_URL}}\n🌐 {website}",

        ("programa|programas|courses" if lang == "es" else
         "programme|programmes|cours" if lang == "fr" else
         "program|programs|course|english"):
            "{PROGRAMS}",

        ("costos|precio|fees|pagar" if lang == "es" else
         "coût|cout|prix|frais|payer|fees|price|pay" if lang == "fr" else
         "cost|price|fees|pay"):
            i18n.get("free_text", "💵 Our courses are free.") + f" {website}"
    }

def build_matchers(lang: str) -> List[Matcher]:
    data = load_faq(lang)
    matchers: List[Matcher] = []
    for patt, ans in data.items():
        matchers.append(Matcher(pattern=re.compile(patt, flags=re.IGNORECASE), answer=ans))
    return matchers

# ------------------------------ UI helpers ------------------------------
def t(lang: str, key: str) -> str:
    i18n = I18N.get(lang, {})
    strings = i18n.get("strings", {})
    default_strings = {
        "welcome": "Hi! I’m the *International Center* assistant. How can I help you today?",
        "help": "Type your question (e.g., *schedule*, *apply*, *location*). Use /menu or /lang.",
        "lang_set": "✅ Language updated.",
        "no_match": f"I couldn’t find an exact answer 🤔. Check {DEFAULT_CONFIG['website_url']} or use /menu.",
        "choose_language": "Choose language / Elige idioma / Choisissez la langue:"
    }
    return strings.get(key, default_strings.get(key, key))

def menu_keyboard(lang: str) -> InlineKeyboardMarkup:
    i18n = I18N.get(lang, {})
    m = i18n.get("menu", {})
    return InlineKeyboardMarkup([
        [InlineKeyboardButton(m.get("programs", "📚 Programs"), callback_data="programs")],
        [InlineKeyboardButton(m.get("schedule", "🗓️ Schedule"), callback_data="schedule")],
        [InlineKeyboardButton(m.get("location", "📍 Location"), callback_data="location")],
        [InlineKeyboardButton(m.get("faq", "❓ FAQ"), callback_data="faq")],
        [InlineKeyboardButton(m.get("language", "🌐 Language"), callback_data="langmenu")],  # botón de idioma
        [InlineKeyboardButton(m.get("site", "🌐 Website"), url=CONFIG["website_url"])]
    ])

def lang_keyboard() -> InlineKeyboardMarkup:
    # Construye botones para todos los idiomas detectados
    row = []
    rows = []
    for code, name in LANGS.items():
        row.append(InlineKeyboardButton(name, callback_data=f"setlang_{code}"))
        if len(row) == 3:
            rows.append(row); row = []
    if row:
        rows.append(row)
    return InlineKeyboardMarkup(rows)

def get_lang(context: ContextTypes.DEFAULT_TYPE) -> str:
    lang = context.user_data.get("lang")
    if lang in LANGS:
        return lang
    # default_lang válido o primer idioma disponible
    return CONFIG.get("default_lang", "en") if CONFIG.get("default_lang") in LANGS else next(iter(LANGS.keys()))

# ------------------------------- Handlers ---------------------------------
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
    lang = get_lang(context)
    await update.message.reply_text(
        with_hint(t(lang, "welcome").replace("{WEBSITE_URL}", CONFIG["website_url"])),
        reply_markup=menu_keyboard(lang),
        parse_mode="Markdown"
    )

async def help_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):
    lang = get_lang(context)
    await update.message.reply_text(
        with_hint(t(lang, "help").replace("{WEBSITE_URL}", CONFIG["website_url"]))
    )

async def menu_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):
    lang = get_lang(context)
    await update.message.reply_text(with_hint("👇"), reply_markup=menu_keyboard(lang))

async def lang_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE):
    # /lang <code>  o /lang (muestra teclado con idiomas)
    if context.args:
        code = context.args[0].lower()
        if code in LANGS:
            context.user_data["lang"] = code
            await update.message.reply_text(with_hint(t(code, "lang_set")))
            return
    await update.message.reply_text(with_hint(t(get_lang(context), "choose_language")), reply_markup=lang_keyboard())

async def on_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
    query = update.callback_query
    data = query.data
    await query.answer()

    if data.startswith("setlang_"):
        code = data.split("_", 1)[1]
        if code in LANGS:
            context.user_data["lang"] = code
            await query.edit_message_text(with_hint(t(code, "lang_set")))
        return

    lang = get_lang(context)
    i18n = I18N.get(lang, {})

    if data == "programs":
        text = i18n.get("programs_text", "📚 Programs. {WEBSITE_URL}")
        kb = InlineKeyboardMarkup([
            [InlineKeyboardButton(i18n.get("menu", {}).get("site", "🌐 Website"), url=CONFIG["website_url"])]
        ])
        await query.edit_message_text(
            with_hint(text.replace("{WEBSITE_URL}", CONFIG["website_url"])),
            reply_markup=kb,
            parse_mode="Markdown",
            disable_web_page_preview=True
        )

    elif data == "schedule":
        text = i18n.get("schedule_text", f"🗓️ See schedules on: {CONFIG['website_url']}")
        await query.edit_message_text(with_hint(text.replace("{WEBSITE_URL}", CONFIG["website_url"])))

    elif data == "location":
        addr = i18n.get("address", "80 Maiden Lane, 13th Floor, New York, NY 10028")
        open_map_label = i18n.get("open_map_label", "🗺️ Open map")
        site_label = i18n.get("menu", {}).get("site", "🌐 Website")
        msg = f"📍 {addr}"
        kb = InlineKeyboardMarkup([
            [InlineKeyboardButton(open_map_label, url=CONFIG["map_url"])],
            [InlineKeyboardButton(site_label, url=CONFIG["website_url"])],
        ])
        await query.edit_message_text(with_hint(msg), reply_markup=kb)

    elif data == "faq":
        hint = i18n.get("faq_hint", t(lang, "help"))
        await query.edit_message_text(with_hint(hint), parse_mode="Markdown")

    elif data == "langmenu":
        # Muestra el selector de idiomas detectados (según i18n_*.json)
        await query.edit_message_text(
            with_hint(t(get_lang(context), "choose_language")),
            reply_markup=lang_keyboard()
        )

def answer_from_faq(text: str, lang: str) -> str:
    i18n = I18N.get(lang, {})
    programs = i18n.get("programs_text", "")
    addr = i18n.get("address", "80 Maiden Lane, 13th Floor, New York, NY 10028")
    map_label = i18n.get("open_map_label", "🗺️ Map")

    for m in MATCHERS[lang]:
        if m.pattern.search(text):
            ans = m.answer
            return (ans
                    .replace("{WEBSITE_URL}", CONFIG["website_url"])
                    .replace("{MAP_URL}", CONFIG["map_url"])
                    .replace("{MAP_LABEL}", map_label)
                    .replace("{ADDRESS}", addr)
                    .replace("{PROGRAMS}", programs))
    return t(lang, "no_match").replace("{WEBSITE_URL}", CONFIG["website_url"])

async def on_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
    lang = get_lang(context)
    user_text = update.message.text or ""
    reply = answer_from_faq(user_text, lang)
    await update.message.reply_text(with_hint(reply), disable_web_page_preview=True, parse_mode="Markdown")

# --------------------------------- Main ----------------------------------
def init_runtime():
    global CONFIG, I18N, LANGS, MATCHERS

    # Config
    CONFIG = load_config()

    # Idiomas detectados por archivos i18n_*.json
    discovered = discover_languages()
    if not discovered:
        # como mínimo, define EN por defecto si no hay i18n_*.json
        discovered = {
            "en": {"name": "English", "i18n": {
                "name": "English",
                "menu": {"programs": "📚 Programs", "schedule": "🗓️ Schedule", "location": "📍 Location", "faq": "❓ FAQ", "site": "🌐 Website", "language": "🌐 Language"},
                "strings": {"welcome": "Hi! I’m the *International Center* assistant.",
                            "help": "Type your question (e.g., *schedule*, *apply*, *location*). Use /menu or /lang.",
                            "lang_set": "✅ Language updated.",
                            "no_match": "I couldn’t find an exact answer 🤔. Check {WEBSITE_URL} or use /menu.",
                            "choose_language": "Choose language:"},
                "programs_text": "📚 Programs. {WEBSITE_URL}",
                "schedule_text": "🗓️ See schedules on: {WEBSITE_URL}",
                "address": "80 Maiden Lane, 13th Floor, New York, NY 10028",
                "open_map_label": "🗺️ Open map",
                "faq_hint": "Type keywords like: *schedule*, *apply*, *location*, *cost*."
            }}
        }

    I18N = {code: data["i18n"] for code, data in discovered.items()}
    LANGS = {code: data["name"] for code, data in discovered.items()}

    # Matchers por idioma (FAQ)
    MATCHERS = {code: build_matchers(code) for code in LANGS.keys()}

if __name__ == "__main__":
    logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO)
    if not TOKEN:
        raise SystemExit("Missing TELEGRAM_TOKEN in environment (.env)")

    init_runtime()

    app = ApplicationBuilder().token(TOKEN).build()
    app.add_handler(CommandHandler("start", start))
    app.add_handler(CommandHandler("help", help_cmd))
    app.add_handler(CommandHandler("menu", menu_cmd))
    app.add_handler(CommandHandler("lang", lang_cmd))
    app.add_handler(CallbackQueryHandler(on_callback))
    app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, on_text))

    logging.info("IC bot v3 is running (polling)...")
    app.run_polling(drop_pending_updates=True)
