"""Acciones disparadas por frases dichas por el bot (p. ej. TE TRANSFIERO)."""

from __future__ import annotations

import json
import logging
import re
import unicodedata
from dataclasses import dataclass
from typing import Any

from config import Settings

logger = logging.getLogger(__name__)

# Frases por defecto si no hay archivo / JSON en .env
_DEFAULT_TRIGGERS: list[dict[str, Any]] = [
    {
        "phrase": "TE TRANSFIERO",
        "action": "transfer",
        "target": "111565309188",
        "speak_phrase": True,
    }
]


@dataclass(frozen=True)
class BotActionTrigger:
    phrase: str
    action: str
    target: str = ""
    speak_phrase: bool = True

    def matches(self, text: str) -> bool:
        hay = _normalize(text)
        needle = _normalize(self.phrase)
        return bool(needle) and needle in hay


def _normalize(text: str) -> str:
    """Minúsculas, sin acentos, espacios colapsados — para match tolerante."""
    raw = (text or "").strip().lower()
    nfkd = unicodedata.normalize("NFKD", raw)
    without_accents = "".join(c for c in nfkd if not unicodedata.combining(c))
    return re.sub(r"\s+", " ", without_accents).strip()


def _parse_items(raw: list[Any]) -> list[BotActionTrigger]:
    out: list[BotActionTrigger] = []
    for item in raw:
        if not isinstance(item, dict):
            continue
        phrase = str(item.get("phrase") or "").strip()
        action = str(item.get("action") or "").strip().lower()
        if not phrase or not action:
            continue
        out.append(
            BotActionTrigger(
                phrase=phrase,
                action=action,
                target=str(item.get("target") or "").strip(),
                speak_phrase=bool(item.get("speak_phrase", True)),
            )
        )
    return out


def load_bot_action_triggers(settings: Settings) -> list[BotActionTrigger]:
    """Carga triggers: BOT_ACTION_TRIGGERS (JSON) > archivo > defaults."""
    inline = (settings.bot_action_triggers or "").strip()
    if inline:
        try:
            data = json.loads(inline)
            if isinstance(data, list):
                triggers = _parse_items(data)
                if triggers:
                    return triggers
        except json.JSONDecodeError as exc:
            logger.error("BOT_ACTION_TRIGGERS JSON inválido: %s", exc)

    path = settings.resolve_prompt_path(settings.bot_action_triggers_file)
    if path:
        try:
            data = json.loads(path.read_text(encoding="utf-8"))
            if isinstance(data, list):
                triggers = _parse_items(data)
                if triggers:
                    logger.info(
                        "Bot action triggers cargados desde %s (%d)",
                        path,
                        len(triggers),
                    )
                    return triggers
        except (OSError, json.JSONDecodeError) as exc:
            logger.error("No se pudo leer %s: %s", path, exc)

    return _parse_items(_DEFAULT_TRIGGERS)


def find_trigger(
    text: str, triggers: list[BotActionTrigger]
) -> BotActionTrigger | None:
    """Primera frase encontrada en el texto del bot (orden del archivo)."""
    for trigger in triggers:
        if trigger.matches(text):
            return trigger
    return None


def strip_phrase_from_speech(text: str, phrase: str) -> str:
    """Quita la frase trigger del texto a sintetizar (si speak_phrase=false)."""
    if not phrase:
        return text
    pattern = re.compile(re.escape(phrase), re.IGNORECASE)
    cleaned = pattern.sub(" ", text or "")
    return re.sub(r"\s+", " ", cleaned).strip()
