"""Smart teach — simplified, robust, no silent failures."""
from __future__ import annotations

import asyncio
import logging
import random
import time
from typing import Optional

from telegram import Update
from telegram.constants import ParseMode
from telegram.error import BadRequest, Forbidden
from telegram.ext import ContextTypes

from bot import db
from bot.decorators import admin_only
from bot.persian_router import register_mixed

logger = logging.getLogger(__name__)

# ───────── Persian normalization ─────────
def _norm(text: str) -> str:
    text = text.strip().lower()
    text = text.replace("ي", "ی").replace("ك", "ک").replace("ة", "ه")
    text = text.replace("ۀ", "ه").replace("أ", "ا").replace("إ", "ا")
    text = text.replace("ؤ", "و").replace("ئ", "ی")
    text = text.replace("\u200c", " ")
    import re
    text = re.sub(r"[^\w\s\d]", " ", text)
    text = re.sub(r"\s+", " ", text).strip()
    return text


# ───────── Template vars ─────────
def _apply_template(text: str, update: Update) -> str:
    user = update.effective_user
    chat = update.effective_chat
    now = time.localtime()
    replacements = {
        "{user}": user.first_name if user else "",
        "{name}": user.full_name if user else "",
        "{username}": f"@{user.username}" if user and user.username else (user.first_name or ""),
        "{chat}": chat.title if chat else "",
        "{id}": str(user.id) if user else "",
        "{random}": str(random.randint(1, 1000)),
        "{time}": f"{now.tm_hour:02d}:{now.tm_min:02d}",
        "{hour}": str(now.tm_hour),
        "{day}": ["دوشنبه", "سه‌شنبه", "چهارشنبه", "پنجشنبه", "جمعه", "شنبه", "یکشنبه"][now.tm_wday],
        "{reaction}": random.choice(["👍", "❤️", "🔥", "💪", "😊", "🎉", "✨", "🌸", "💚"]),
    }
    for key, val in replacements.items():
        text = text.replace(key, val)
    return text


# ───────── Learn ─────────
@admin_only
async def teach_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    if not update.message:
        return
    chat = update.effective_chat
    msg = update.message
    text = msg.text or ""
    user_id = update.effective_user.id if update.effective_user else 0

    # Reply-based learn
    if msg.reply_to_message and "=" not in text.split("--")[0]:
        replied = msg.reply_to_message
        parts = text.split(maxsplit=1)
        if len(parts) < 2:
            await msg.reply_text("Usage: reply to a message + say: یادبگیر [trigger]")
            return

        trigger = parts[1].strip().lower()
        response = replied.text or replied.caption or ""
        response_type = "text"
        file_id = None

        if replied.sticker:
            response_type, file_id = "sticker", replied.sticker.file_id
        elif replied.photo:
            response_type, file_id = "photo", replied.photo[-1].file_id
        elif replied.voice:
            response_type, file_id = "voice", replied.voice.file_id
        elif replied.video:
            response_type, file_id = "video", replied.video.file_id
        elif replied.animation:
            response_type, file_id = "animation", replied.animation.file_id

        if not response and not file_id:
            await msg.reply_text("This message has no content to learn.")
            return

        resp_text = response or file_id or trigger
        await db.add_learned_response(
            chat.id, trigger, resp_text, user_id,
            response_type=response_type, file_id=file_id,
        )
        icon = "📸" if response_type != "text" else "💬"
        await msg.reply_text(f"{icon} Learned: «{trigger}»")
        return

    # Inline teach: یادبگیر [trigger] = [response]
    if "=" in text:
        # Parse flags
        weight, delay = 1.0, 0.0
        import re as _re
        wm = _re.search(r'--weight=(\d+\.?\d*)', text)
        if wm:
            weight = max(0.1, min(10.0, float(wm.group(1))))
            text = text.replace(wm.group(0), "")
        dm = _re.search(r'--delay=(\d+\.?\d*)', text)
        if dm:
            delay = max(0.0, min(5.0, float(dm.group(1))))
            text = text.replace(dm.group(0), "")

        parts = text.split("=", 1)
        if len(parts) < 2:
            await msg.reply_text("Usage: یادبگیر [trigger] = [response]")
            return

        cmd_part = parts[0].strip()
        response = parts[1].strip()
        cmd_words = cmd_part.split(maxsplit=1)
        trigger = cmd_words[1].strip().lower() if len(cmd_words) > 1 else ""

        if not trigger or not response:
            await msg.reply_text("Both trigger and response are required.")
            return

        await db.add_learned_response(
            chat.id, trigger, response, user_id,
            weight=weight, delay=delay,
        )
        await msg.reply_text(f"Learned: «{trigger}» → {response[:80]}")
        return

    # Help
    await msg.reply_text(
        "🎯 <b>Teach Commands:</b>\n\n"
        "1️⃣ <code>یادبگیر [trigger] = [response]</code>\n"
        "2️⃣ Reply + <code>یادبگیر [trigger]</code>\n"
        "3️⃣ <code>فراموش کن [trigger]</code>\n"
        "4️⃣ <code>یادگرفته‌ها</code> — list all\n\n"
        "<b>Vars:</b> {user} {name} {username} {chat} {time} {day} {random}\n"
        "<b>Flags:</b> --weight=2 --delay=1\n"
        "<b>Multi:</b> response1 || response2 || response3",
        parse_mode=ParseMode.HTML,
    )


# ───────── Unlearn ─────────
@admin_only
async def unteach_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    if not update.message:
        return
    parts = (update.message.text or "").split(maxsplit=1)
    if len(parts) < 2:
        await update.message.reply_text("Usage: فراموش کن [trigger]")
        return
    trigger = parts[1].strip().lower()
    count = await db.remove_learned_response(update.effective_chat.id, trigger)
    await update.message.reply_text(f"Deleted {count} response(s) for «{trigger}»")


# ───────── List learned ─────────
async def learned_cmd(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    if not update.message:
        return
    chat_id = update.effective_chat.id
    items = await db.get_learned_responses(chat_id)
    if not items:
        await update.message.reply_text("Nothing learned yet. Use: یادبگیر [trigger] = [response]")
        return

    groups: dict[str, list] = {}
    for item in items:
        t = item["trigger_text"]
        if t not in groups:
            groups[t] = []
        groups[t].append(item)

    text = f"📊 Learned responses: {len(items)} total, {len(groups)} triggers\n\n"
    for trigger, resp_list in sorted(groups.items(), key=lambda x: -len(x[1])):
        text += f"• «{trigger}» — {len(resp_list)} response(s)\n"

    await update.message.reply_text(text)


# ───────── Check learned (called from listener) ─────────
async def check_learned(update: Update, context: ContextTypes.DEFAULT_TYPE) -> bool:
    """Check if message matches a learned response. Returns True if handled."""
    message = update.message
    if not message or not message.text:
        return False

    chat_id = update.effective_chat.id
    uid = update.effective_user.id if update.effective_user else 0

    # Skip private chats
    if update.effective_chat.type == "private":
        return False

    # Cooldown
    if await db.check_cooldown(chat_id, "_global", 3):
        return False

    # Find match
    match = await db.find_learned_response(chat_id, message.text)
    if not match:
        return False

    # Per-trigger cooldown
    if await db.check_cooldown(chat_id, match["trigger_text"], 8):
        return False

    # Apply template
    raw = match["response_text"]
    response = _apply_template(raw, update)
    rtype = match.get("response_type", "text")
    file_id = match.get("file_id")
    delay = match.get("delay", 0.0)

    # Multi-response
    if "||" in response and rtype == "text":
        response = random.choice([p.strip() for p in response.split("||")])

    # Delay
    if delay > 0:
        await asyncio.sleep(delay)
    elif random.random() < 0.3 and len(response) > 15:
        await asyncio.sleep(random.uniform(0.3, 0.8))

    # Send
    try:
        if rtype == "sticker" and file_id:
            await message.reply_sticker(file_id)
        elif rtype == "photo" and file_id:
            await message.reply_photo(file_id, caption=response if response and response != file_id else None)
        elif rtype == "voice" and file_id:
            await message.reply_voice(file_id)
        elif rtype == "video" and file_id:
            await message.reply_video(file_id)
        elif rtype == "animation" and file_id:
            await message.reply_animation(file_id)
        else:
            await message.reply_text(response, parse_mode=ParseMode.HTML)
    except (BadRequest, Forbidden) as e:
        logger.warning(f"Teach response failed: {e}")
        try:
            await message.reply_text(response)
        except (BadRequest, Forbidden):
            pass

    return True


# ───────── Register ─────────
def register(app) -> None:
    register_mixed(
        app,
        {"teach": teach_cmd, "unteach": unteach_cmd, "learned": learned_cmd},
        {
            "یادبگیر": teach_cmd,
            "یاد بگیر": teach_cmd,
            "به من یاد بده": teach_cmd,
            "فراموش کن": unteach_cmd,
            "یادگرفته‌ها": learned_cmd,
            "چی یاد گرفتی": learned_cmd,
            "آمار یادگیری": learned_cmd,
        },
    )
