"""Notfall-Erkennung und Eskalation (Senioren-Kontext).

Zweistufig:
1. Schnelle Stichwort-Heuristik (`detect` / `handle_emergency`) im Hot-Path -> 0 Latenz.
2. LLM-Klassifikation (`schedule_llm_emergency_check`) als Hintergrund-Task, der NUR
   laeuft, wenn die Heuristik nichts fand -> faengt verpasste Formulierungen, ohne die
   Antwortlatenz zu erhoehen.

Die erkannten Textauszuege sind hochsensibel und werden bewusst protokolliert
(DSGVO beachten: Einwilligung, Aufbewahrung, Zugriff).
"""

import asyncio
import logging

import httpx

from app.config import settings, Settings
from app.metrics import metrics

logger = logging.getLogger(__name__)

# Referenzen auf laufende Hintergrund-Tasks halten (sonst GC-gefaehrdet).
_pending: set[asyncio.Task] = set()

# Phrasen je Kategorie (de/en), bewusst eher spezifisch gegen Fehlalarme.
_PATTERNS: dict[str, list[str]] = {
    "medical": [
        "brustschmerz", "schmerzen in der brust", "kann nicht atmen", "keine luft",
        "atemnot", "herzinfarkt", "schlaganfall", "bewusstlos", "gestuerzt", "gestürzt",
        "gefallen und komme nicht hoch", "starke blutung",
        "chest pain", "can't breathe", "cannot breathe", "heart attack", "stroke",
        "i fell and can't", "bleeding badly",
    ],
    "self_harm": [
        "nicht mehr leben", "mich umbringen", "selbstmord", "suizid", "will sterben",
        "kill myself", "end my life", "suicide", "want to die",
    ],
    "help": [
        "notruf", "notarzt", "krankenwagen", "ruf einen arzt", "es brennt",
        "call an ambulance", "call 911", "call 112",
    ],
}


def detect(text: str):
    """Liefert (category, matched_phrase) oder None."""
    if not text:
        return None
    low = text.lower()
    for category, phrases in _PATTERNS.items():
        for phrase in phrases:
            if phrase in low:
                return category, phrase
    return None


async def _fire_webhook(url: str, user, category: str, snippet: str) -> None:
    try:
        async with httpx.AsyncClient(timeout=5) as client:
            await client.post(
                url,
                json={
                    "user_id": user.id,
                    "display_name": user.display_name,
                    "category": category,
                    "text": snippet,
                },
            )
    except Exception:  # noqa: BLE001 - best effort, darf den Chat nicht brechen
        metrics.inc("emergency_webhook_error_total")


def _escalate(user, category: str, snippet: str, store, cfg: Settings, source: str) -> None:
    """Protokolliert + eskaliert einen erkannten Notfall (Log, Metrik, Webhook)."""
    store.log_emergency(user.id, category, snippet)
    metrics.inc("emergency_total", {"category": category, "source": source})
    if cfg.emergency_webhook_url:
        try:
            asyncio.get_running_loop().create_task(
                _fire_webhook(cfg.emergency_webhook_url, user, category, snippet)
            )
        except RuntimeError:
            pass  # kein laufender Event-Loop (z. B. im Test) -> Webhook ueberspringen


def handle_emergency(user, text: str, store, cfg: Settings = settings):
    """Stufe 1: Stichwort-Heuristik. Erkennt, protokolliert und eskaliert sofort.

    Gibt {"category", "matched"} zurueck, wenn etwas erkannt wurde, sonst None.
    Der Webhook (falls konfiguriert) wird nicht-blockierend ausgeloest.
    """
    match = detect(text)
    if not match:
        return None
    category, phrase = match
    _escalate(user, category, text[:500], store, cfg, source="keyword")
    return {"category": category, "matched": phrase}


async def _llm_check(user, text: str, store, cfg: Settings, on_emergency) -> None:
    """Hintergrund: LLM-Klassifikation + Eskalation (best-effort)."""
    try:
        from app.safety.llm_classifier import classify_emergency

        result = await classify_emergency(text, cfg)
        if not result:
            return
        category = result["category"]
        _escalate(user, category, text[:500], store, cfg, source="llm")
        logger.info(
            "llm-emergency: %s (conf=%.2f) fuer %s", category, result["confidence"], user.id
        )
        if on_emergency is not None:
            await on_emergency(category)
    except Exception:  # best-effort: darf den Turn nie brechen
        logger.exception("llm-emergency-check fehlgeschlagen (ignoriert)")


def schedule_llm_emergency_check(user, text: str, store, keyword_hit,
                                 cfg: Settings = settings, on_emergency=None):
    """Stufe 2: plant die LLM-Klassifikation als Hintergrund-Task.

    Laeuft NUR, wenn die Stichwort-Heuristik nichts fand (`keyword_hit` ist None) und
    die LLM-Stufe aktiviert ist. `on_emergency(category)` (async) wird bei Treffer
    aufgerufen (z. B. WS-Event). Gibt den Task zurueck oder None - blockiert nie.
    """
    if keyword_hit is not None or not cfg.emergency_llm_enabled:
        return None
    if not text or not text.strip():
        return None
    try:
        task = asyncio.get_running_loop().create_task(
            _llm_check(user, text, store, cfg, on_emergency)
        )
    except RuntimeError:
        return None  # kein laufender Event-Loop (z. B. Test) -> ueberspringen
    _pending.add(task)
    task.add_done_callback(_pending.discard)
    return task
