"""Intentions vocales locales (lecture seule) — court-circuitent le LLM.

Trois intentions déterministes, reconnues sur le transcript avant l'appel au
STT-server :

  • « ouvre / lance / montre <service> »     → ouvre la page dans le navigateur
  • « état du cluster / des services »        → résumé de la santé du portail
  • « combien sur mon ghostfolio »            → valeur du portefeuille (API Ghostfolio)

`route_intent()` renvoie une phrase à dire si une intention matche, sinon None
(la question part alors au LLM comme d'habitude).
"""

from __future__ import annotations

import re
from typing import Any, Callable

from .registry import Service, _norm, match_service

# Verbes d'ouverture (normalisés, sans accent)
_OPEN_VERBS = (
    "ouvre", "ouvrir", "ouvres", "lance", "lancer", "affiche", "afficher",
    "montre", "montrer", "accede", "acceder", "va sur", "amene moi sur",
)
# Mots vides retirés en tête de la cible (« ouvre LE grafana » → « grafana »)
_FILLERS = {"le", "la", "les", "l", "mon", "ma", "mes", "moi", "sur", "vers", "du", "de", "des", "un", "une"}

_GHOSTFOLIO_WORDS = ("ghostfolio", "portefeuille", "portfolio")
_GHOSTFOLIO_QUALIFIERS = (
    "combien", "valeur", "vaut", "vaux", "solde", "montant", "total",
    "cote", "riche", "argent", "capital",
)
_STATUS_WORDS = ("etat", "statut", "sante", "forme", "fonctionne", "marche", "va")
_STATUS_SCOPE = ("cluster", "service", "services", "homelab", "infra", "pods", "tout")


def _extract_open_target(norm: str) -> str | None:
    """Renvoie ce qui suit un verbe d'ouverture, nettoyé, ou None si pas de verbe."""
    for verb in _OPEN_VERBS:
        m = re.search(rf"\b{re.escape(verb)}\b\s+(.*)", norm)
        if m:
            tail = m.group(1).strip()
            words = [w for w in tail.split() if w not in _FILLERS]
            return " ".join(words).strip() or None
    return None


def route_intent(
    text: str,
    *,
    services: list[Service],
    open_fn: Callable[[str], None],
    status_fn: Callable[[], str],
    ghostfolio_fn: Callable[[], str],
) -> str | None:
    norm = _norm(text)
    if not norm:
        return None

    # 1) Ghostfolio — valeur (avant « ouvre », sinon « ouvre ghostfolio » serait capté)
    if any(w in norm for w in _GHOSTFOLIO_WORDS) and any(q in norm for q in _GHOSTFOLIO_QUALIFIERS):
        return ghostfolio_fn()

    # 2) État du cluster / des services
    if any(w in norm for w in _STATUS_WORDS) and any(s in norm for s in _STATUS_SCOPE):
        return status_fn()

    # 3) Ouvrir un service
    target = _extract_open_target(norm)
    if target:
        svc = match_service(services, target)
        if svc is not None:
            open_fn(svc.id)
            return f"J'ouvre {svc.name}."
    return None


def summarize_status(status_msg: dict[str, Any] | None, services: list[Service]) -> str:
    """Résumé parlable de la santé du portail (depuis le dernier portal-status)."""
    if not status_msg or not status_msg.get("services"):
        return "Je récupère encore l'état des services, réessaie dans un instant."
    names = {s.id: s.name for s in services}
    svc_status = status_msg.get("services", {})
    down, degraded, ok = [], [], 0
    for sid, st in svc_status.items():
        name = names.get(sid, sid)
        h = (st or {}).get("health")
        if h == "down":
            down.append(name)
        elif h == "degraded":
            degraded.append(name)
        elif h == "ok":
            ok += 1
    total = len(svc_status)
    alerts = status_msg.get("alerts_total")

    if not down and not degraded:
        msg = f"Tout va bien : les {total} services du homelab sont en ligne."
    else:
        parts = []
        if down:
            parts.append(_enum(down) + (" est hors ligne" if len(down) == 1 else " sont hors ligne"))
        if degraded:
            parts.append(_enum(degraded) + (" est dégradé" if len(degraded) == 1 else " sont dégradés"))
        msg = "Attention : " + " ; ".join(parts) + "."
        if ok:
            msg += f" Les {ok} autres sont en ligne."
    if alerts:
        msg += f" Il y a {alerts} alerte{'s' if alerts > 1 else ''} active{'s' if alerts > 1 else ''}."
    return msg


def _enum(items: list[str]) -> str:
    """['A','B','C'] → 'A, B et C'."""
    if len(items) <= 1:
        return items[0] if items else ""
    return ", ".join(items[:-1]) + " et " + items[-1]
