"""Persian natural language command router."""
from __future__ import annotations

import difflib
import logging
import re

from telegram import Update
from telegram.ext import ContextTypes
from bot.services.conversation import should_continue_conversation

logger = logging.getLogger(__name__)

# Global registry of Persian phrase -> handler
_persian_handlers: dict[str, callable] = {}

INTENT_ALIASES: dict[str, tuple[str, ...]] = {
    "بن": ("بن کن", "بنش کن", "بنش", "اخراج دائم"),
    "سکوت": ("ساکت کن", "میوت", "خفه کن"),
    "اخطار": ("هشدار", "اخطار بده", "warn"),
    "قفل": ("لاک", "قفل کن", "ببند"),
    "هوش مصنوعی": ("ai", "جی پی تی", "جمینای"),
}

BOT_NAMES = (
    "بابی",
    "bobi",
    "bob",
)


def register_persian(phrase: str, handler: callable) -> None:
    _persian_handlers[phrase.lower().strip()] = handler


def _normalize(text: str) -> str:
    text = text.strip().lower()

    replacements = {
        "ي": "ی",
        "ك": "ک",
        "ة": "ه",
        "ۀ": "ه",
        "أ": "ا",
        "إ": "ا",
        "ؤ": "و",
        "ئ": "ی",
    }

    for old, new in replacements.items():
        text = text.replace(old, new)

    return re.sub(r"\s+", " ", text)


def _expand_intents(text: str) -> str:
    for canonical, aliases in INTENT_ALIASES.items():
        for alias in aliases:
            if alias in text:
                return text.replace(alias, canonical)

    return text


def _fuzzy_match(text: str) -> tuple[str, callable] | None:
    phrases = list(_persian_handlers.keys())

    if not phrases:
        return None

    matched = difflib.get_close_matches(text, phrases, n=1, cutoff=0.72)

    if not matched:
        return None

    phrase = matched[0]

    return phrase, _persian_handlers[phrase]


def _extract_conversation_target(text: str) -> str | None:
    for name in BOT_NAMES:
        if text.startswith(name + " "):
            return text[len(name):].strip(" ،:,")

        if text == name:
            return ""

    return None


def _is_reply_to_bot(update: Update, bot_username: str | None = None) -> bool:
    if not update.message or not update.message.reply_to_message:
        return False

    replied_user = update.message.reply_to_message.from_user

    if not replied_user:
        return False

    if replied_user.is_bot:
        return True

    if bot_username and replied_user.username:
        return replied_user.username.lower() == bot_username.lower()

    return False


def register_mixed(
    app, english_commands: dict, persian_phrases: dict
) -> None:
    """Register both English commands and Persian phrases."""
    from telegram.ext import CommandHandler

    for cmd, handler in english_commands.items():
        app.add_handler(CommandHandler(cmd, handler))
    for phrase, handler in persian_phrases.items():
        register_persian(phrase, handler)


async def dispatch(
    update: Update, context: ContextTypes.DEFAULT_TYPE
) -> bool:
    """Try to dispatch a Persian command. Returns True if handled."""
    if not update.message or not update.message.text:
        return False
    text = _normalize(update.message.text)

    text = _expand_intents(text)

    # Conversational invocation
    conversation = _extract_conversation_target(text)

    if conversation is None and _is_reply_to_bot(update, getattr(context.bot, "username", None)):
        conversation = text

    if (
        conversation is None
        and update.effective_chat
        and update.effective_user
        and should_continue_conversation(
            update.effective_chat.id,
            update.effective_user.id,
            text,
        )
    ):
        conversation = text

    if conversation is not None:
        ai_handler = _persian_handlers.get("هوش مصنوعی")

        if ai_handler:
            context.args = [conversation] if conversation else []

            # Rewrite message text so downstream handlers receive the cleaned prompt.
            if update.message:
                update.message.text = f"هوش مصنوعی {conversation}".strip()

            logger.info("Conversational AI invocation: %s", conversation)

            await ai_handler(update, context)

            return True

    # Check registered phrases
    words = text.split()

    for phrase, handler in _persian_handlers.items():
        phrase_words = phrase.split()

        if len(words) >= len(phrase_words) and words[: len(phrase_words)] == phrase_words:
            original_words = (update.message.text or "").strip().split()
            context.args = original_words[len(phrase_words):]

            await handler(update, context)
            return True

    # Fuzzy matching for typo tolerance
    fuzzy = _fuzzy_match(text)

    if fuzzy:
        phrase, handler = fuzzy

        logger.info("Fuzzy matched '%s' -> '%s'", text, phrase)

        context.args = text.split()[len(phrase.split()):]

        await handler(update, context)

        return True

    return False
