"""Configuration du client STT.

Défauts embarqués (robuste pour pipx). `stt --setup` les écrit dans
~/.config/stt/stt.toml ; au lancement on fusionne le fichier utilisateur par-dessus.

Le client ne contient PLUS le cerveau : il envoie le texte au STT-server (URL paramétrable).
"""

from __future__ import annotations

import tomllib
from pathlib import Path
from typing import Any

CONFIG_DIR = Path.home() / ".config" / "stt"
CONFIG_PATH = CONFIG_DIR / "stt.toml"
DATA_DIR = Path.home() / ".local" / "share" / "stt"

# Noms courts → alias LiteLLM (pour --model et la commande /model)
MODEL_PRESETS = {
    "hermes": "hermes-default",   # Qwen3-8B local (défaut, gratuit)
    "qwen": "qwen3-8b",
    "claude": "claude-sonnet-4-6",  # Claude (facturé)
    "opus": "claude-opus-4-7",
}


def resolve_model(name: str) -> str:
    """Nom court → alias LiteLLM (ou renvoie tel quel si déjà un alias)."""
    return MODEL_PRESETS.get(name, name)


def _pod_metrics(ns: str, pod_re: str) -> list[dict]:
    """Jeu de métriques standard pour les pods d'un service (page détail HUD).

    Redémarrages + uptime : kube-state-metrics (toujours scrappé). Mémoire + CPU :
    cAdvisor/kubelet (`hide_if_empty` → la carte disparaît si non disponible). Les
    requêtes s'agrègent à une seule valeur (sum/max) → le poller prend la 1re.
    """
    sel = f'namespace="{ns}",pod=~"{pod_re}"'
    csel = f'namespace="{ns}",pod=~"{pod_re}",container!="",container!="POD"'
    return [
        {"label": "Redémarrages",
         "prom": f"sum(kube_pod_container_status_restarts_total{{{sel}}})", "unit": "count"},
        {"label": "Démarré depuis",
         "prom": f"time()-max(kube_pod_start_time{{{sel}}})", "unit": "duration"},
        {"label": "Mémoire",
         "prom": f"sum(container_memory_working_set_bytes{{{csel}}})",
         "unit": "bytes", "hide_if_empty": True},
        {"label": "CPU",
         "prom": f"sum(rate(container_cpu_usage_seconds_total{{{csel}}}[5m]))",
         "unit": "cpu", "hide_if_empty": True},
    ]

DEFAULT_CONFIG: dict[str, Any] = {
    "server": {
        # STT-server (in-cluster) — joignable via Traefik / wildcard *.lab.local
        "url": "http://stt.lab.local",
        "timeout_sec": 90,
        # Modèle demandé au serveur (alias LiteLLM, ou nom court ci-dessous)
        "model": "hermes-default",
    },
    "voice": {
        # Wake word principal : « Asa ». Dire « Asa » la réveille ; « Asa stop » la rendort.
        "wake_word": "asa",
        # Variantes tolérées du wake word « Asa » — formes COMPACTES (déaccentuées, sans
        # espace). L'ASR découpe « Asa » en « a so » / « à ça » / « ah ça »… → on joint les
        # 1-2 premiers mots avant de comparer. Ajuste cette liste si ton ASR rend autrement.
        "wake_aliases": ["asa", "aza", "assa", "aca", "aco", "aso", "asso", "azo",
                         "ahca", "ahsa", "aica", "haza", "hassa", "aha"],
        # Mots/phrases qui remettent Asa en veille quand elle est éveillée (sous-chaîne).
        "sleep_words": ["stop", "dors", "au revoir", "bonne nuit", "fin", "silence", "tais-toi"],
        # ASR : "whisper" (faster-whisper CPU, défaut) | "onnx" (Parakeet/Canary/Nemotron)
        "asr_engine": "whisper",
        "whisper_model": "large-v3",
        # onnx-asr (si asr_engine="onnx") — modèle multilingue + execution providers.
        # CPU par défaut ; pour le GPU AMD : ["ROCMExecutionProvider", "CPUExecutionProvider"].
        "onnx_model": "nemo-parakeet-tdt-0.6b-v3",
        "onnx_providers": ["CPUExecutionProvider"],
        # TTS (voix d'Asa) : "piper" (défaut, rapide) | "kokoro" (plus naturel, ONNX/CPU).
        # Pour Kokoro : `stt --install-kokoro` (modèle) + `pipx inject stt kokoro-onnx`.
        "tts_engine": "piper",
        # Volume de la voix : gain appliqué au TTS (1.0 = normal, 0.0 = muet, 2.0 = amplifié).
        # Réglable à chaud depuis le HUD (Réglages → « Volume de la voix »).
        "tts_volume": 1.0,
        "piper_voice": "fr_FR-upmc-medium",
        # Kokoro — voix FR « ff_siwis » (femme). Vitesse 1.0 ; lang fr-fr (phonémisation espeak-ng).
        "kokoro_voice": "ff_siwis",
        "kokoro_speed": 1.0,
        "kokoro_lang": "fr-fr",
        "language": "fr",
        "silence_sec": 1.2,
        "min_speech_sec": 0.6,
        "chat_timeout_sec": 60,
        # Transcription partielle live (texte qui se forme dans le HUD pendant qu'on parle).
        # Clé `partial_transcription` volontairement ABSENTE → auto : activée seulement avec
        # l'ASR "onnx" (Parakeet, assez rapide en CPU). Ajouter `partial_transcription = true`
        # (ou false) dans stt.toml pour forcer. Whisper large-v3 CPU est trop lent → laisser auto.
        "partial_interval_sec": 0.5,   # cadence de re-transcription du buffer
        "partial_min_sec": 0.4,        # ne transcrit pas en dessous (bruit)
        "partial_max_sec": 8.0,        # au-delà, on arrête les partiels (coût) — le final suit
    },
    "ui": {
        # theme / avatar : désormais pilotés dans le HUD (Réglages → localStorage),
        # conservés pour compat mais ignorés par le HUD actuel.
        "theme": "arc-reactor",
        "avatar": "default",
        "kiosk": True,
        # window_mode : "app" (fenêtre type Discord) | "kiosk" (plein écran) | "none".
        # Si absent, repli sur kiosk ci-dessus (compat).
        "window_mode": "kiosk",
        "ws_host": "127.0.0.1",
        "ws_port": 9300,
        "http_port": 9301,
    },
    "memory": {
        # cache local de conversation (brut, gitignoré) — la vraie mémoire est côté serveur
        "enabled": True,
        "local_db": str(DATA_DIR / "memory.sqlite"),
    },
    # Portail de services — panneau « Services » du HUD (tuiles + pages détail), santé
    # live, ET commande vocale « ouvre <service> ». Ajouter un service = une entrée ici
    # (ou un bloc [[services]] dans stt.toml, qui remplace alors toute cette liste).
    # Champs : id, name, url, icon, aliases (voix) ; + pour la page détail :
    #   description, health_url (sondé), components[{name, prom}] (PromQL → 1/0),
    #   alerts_match (labels Alertmanager : alerte pertinente si TOUS matchent).
    "services": [
        {
            "id": "ghostfolio", "name": "Ghostfolio",
            "url": "http://ghostfolio.lab.local", "icon": "💰",
            "aliases": ["portefeuille", "portfolio", "ghosto", "bourse", "investissements"],
            "description": "Suivi de portefeuille et d'investissements (actions, crypto). "
                           "Base PostgreSQL sur storage-01 + cache Redis in-cluster.",
            "health_url": "http://ghostfolio.lab.local/api/v1/health",
            "metrics": _pod_metrics("ai", "ghostfolio-.+"),
            "components": [
                {"name": "Application", "prom": 'kube_pod_status_ready{namespace="ai",pod=~"ghostfolio-.+",pod!~"ghostfolio-redis-.+",condition="true"}'},
                {"name": "Redis (cache)", "prom": 'kube_pod_status_ready{namespace="ai",pod=~"ghostfolio-redis-.+",condition="true"}'},
                {"name": "PostgreSQL — storage-01", "prom": 'up{job="storage-01"}'},
            ],
            "alerts_match": {"namespace": "ai"},
        },
        {
            "id": "grafana", "name": "Grafana",
            "url": "http://grafana.lab.local", "icon": "📊",
            "aliases": ["graphana", "metriques", "monitoring", "dashboard", "graphiques"],
            "description": "Tableaux de bord et visualisation des métriques du homelab "
                           "(Prometheus comme source de données).",
            "health_url": "http://grafana.lab.local/api/health",
            "metrics": _pod_metrics("monitoring", ".*grafana.*"),
            "components": [
                {"name": "Pod", "prom": 'kube_pod_status_ready{namespace="monitoring",pod=~".*grafana.*",condition="true"}'},
            ],
            "alerts_match": {"namespace": "monitoring"},
        },
        {
            "id": "argocd", "name": "ArgoCD",
            "url": "http://argocd.lab.local", "icon": "🚢",
            "aliases": ["argo", "argo cd", "deploiements", "gitops"],
            "description": "Déploiement continu GitOps : synchronise les workloads k8s "
                           "depuis le dépôt Git (pattern App-of-Apps).",
            "health_url": "http://argocd.lab.local/healthz",
            "metrics": _pod_metrics("argocd", ".+"),
            "components": [
                {"name": "Pods (server, repo, redis…)", "prom": 'kube_pod_status_ready{namespace="argocd",condition="true"}'},
            ],
            "alerts_match": {"namespace": "argocd"},
        },
        {
            "id": "n8n", "name": "n8n",
            "url": "http://n8n.lab.local", "icon": "🔀",
            "aliases": ["workflows", "automatisation", "nodes", "huit n huit"],
            "description": "Automatisation et workflows (alertes, rapport horaire, worker "
                           "doc Hermès). Base PostgreSQL sur storage-01.",
            "health_url": "http://n8n.lab.local/healthz",
            "metrics": _pod_metrics("ai", "n8n-.+"),
            "components": [
                {"name": "Application", "prom": 'kube_pod_status_ready{namespace="ai",pod=~"n8n-.+",condition="true"}'},
                {"name": "PostgreSQL — storage-01", "prom": 'up{job="storage-01"}'},
            ],
            "alerts_match": {"namespace": "ai"},
        },
        {
            "id": "openwebui", "name": "Open WebUI",
            "url": "http://openwebui.lab.local", "icon": "💬",
            "aliases": ["open web ui", "webui", "chat", "llm", "interface ia"],
            "description": "Interface de chat web vers les LLM du homelab "
                           "(backend LiteLLM sur storage-01).",
            "health_url": "http://openwebui.lab.local/health",
            "metrics": _pod_metrics("ai", "open-webui-.+"),
            "components": [
                {"name": "Application", "prom": 'kube_pod_status_ready{namespace="ai",pod=~"open-webui-.+",condition="true"}'},
                {"name": "LiteLLM — storage-01", "prom": 'up{job="storage-01"}'},
            ],
            "alerts_match": {"namespace": "ai"},
        },
        {
            "id": "prometheus", "name": "Prometheus",
            "url": "http://prometheus.lab.local", "icon": "🔥",
            "aliases": ["prometheus", "metriques brutes", "tsdb"],
            "description": "Collecte et stockage des métriques (TSDB) — scrute hôtes, "
                           "nœuds k8s et services.",
            "health_url": "http://prometheus.lab.local/-/healthy",
            "metrics": _pod_metrics("monitoring", "prometheus-.+"),
            "components": [
                {"name": "Pod", "prom": 'kube_pod_status_ready{namespace="monitoring",pod=~"prometheus-.+",condition="true"}'},
            ],
            "alerts_match": {"namespace": "monitoring"},
        },
        {
            "id": "alertmanager", "name": "Alertmanager",
            "url": "http://alertmanager.lab.local", "icon": "🚨",
            "aliases": ["alertes", "alert manager", "alarmes"],
            "description": "Routage et notification des alertes Prometheus "
                           "(→ webhook Hermès, n8n, e-mail).",
            "health_url": "http://alertmanager.lab.local/-/healthy",
            "metrics": _pod_metrics("monitoring", "alertmanager-.+"),
            "components": [
                {"name": "Pod", "prom": 'kube_pod_status_ready{namespace="monitoring",pod=~"alertmanager-.+",condition="true"}'},
            ],
            "alerts_match": {"namespace": "monitoring"},
        },
    ],
    # Santé live du portail (pages détail). Sondage non bloquant en thread.
    "portal": {
        "status_enabled": True,
        "status_interval_sec": 15,      # cadence de rafraîchissement
        "probe_timeout_sec": 4,
        "prometheus_url": "http://prometheus.lab.local",
        "alertmanager_url": "http://alertmanager.lab.local",
    },
    # Ghostfolio — jeton (« Security token » du compte). SOURCE UNIQUE du jeton :
    # le client le transmet au serveur, qui fait l'appel API (intent « combien sur mon
    # portefeuille » via /v1/portfolio + contexte Ghostfolio). Vide → indisponible.
    "ghostfolio": {
        "access_token": "",
    },
}


def _deep_merge(base: dict, over: dict) -> dict:
    out = dict(base)
    for k, v in over.items():
        if isinstance(v, dict) and isinstance(out.get(k), dict):
            out[k] = _deep_merge(out[k], v)
        else:
            out[k] = v
    return out


def load_config() -> dict[str, Any]:
    if CONFIG_PATH.exists():
        with CONFIG_PATH.open("rb") as f:
            user = tomllib.load(f)
        return _deep_merge(DEFAULT_CONFIG, user)
    return DEFAULT_CONFIG


def write_default_config(force: bool = False) -> Path:
    import tomli_w

    CONFIG_DIR.mkdir(parents=True, exist_ok=True)
    DATA_DIR.mkdir(parents=True, exist_ok=True)
    if CONFIG_PATH.exists() and not force:
        return CONFIG_PATH
    with CONFIG_PATH.open("wb") as f:
        tomli_w.dump(DEFAULT_CONFIG, f)
    return CONFIG_PATH
