"""Las medidas de eficiencia de JARVIS, sacadas del diario.

El diario ya apunta por cada frase: cuanto tardo (`seg`), por donde fue (`via`)
y cuando (`t`). De ahi salen las metricas de rendimiento sin instrumentar nada
del camino caliente: esto solo LEE, y se calcula fuera del hilo que contesta.

## Que se mide y por que importa cada una

  latencia    p50/p95/max del tiempo de respuesta. La mediana dice como va de
              normal; el p95 dice como va cuando va mal, que es lo que se nota.
  reparto     que fraccion va al CEREBRO (lento, ~2-3 s) y cual al CATALOGO
              (instantaneo, salta el modelo). Es la palanca de eficiencia mas
              grande: cuanto mas catalogo, mas rapido el conjunto.
  ruido       que fraccion de lo que oye es Whisper oyendose a si mismo. No es
              velocidad, es calidad de la escucha, y envenena todo lo demas.
  volumen     frases en las ultimas 24 h. Contexto para lo anterior: un p95 malo
              con 4 frases no dice nada.
  rag         hit@5/hit@1 del ultimo benchmark del RAG (informe_rag.txt). Es la
              unica que no sale del diario: es una medida de test, periodica.

Todo sobre una VENTANA reciente (las ultimas MUESTRA frases), no sobre el diario
entero: interesa como va AHORA, no la media historica que nunca cambia.
"""
import os
import re
from datetime import datetime, timedelta

from manos.diario import lee

AQUI = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
INFORME_RAG = os.path.join(AQUI, "datos", "informe_rag.txt")

MUESTRA = 600          # las ultimas N frases: "como va ahora"
CEREBRO = "cerebro"


def _percentil(valores, q):
    if not valores:
        return 0.0
    v = sorted(valores)
    k = (len(v) - 1) * q
    lo, hi = int(k), min(int(k) + 1, len(v) - 1)
    return v[lo] + (v[hi] - v[lo]) * (k - lo)


def _rag():
    """hit@5 y hit@1 del ultimo informe del RAG, si existe."""
    try:
        txt = open(INFORME_RAG, encoding="utf-8").read()
    except OSError:
        return None
    # el bloque CANDIDATO es el que se promociono; si no, el ultimo que haya
    def pct(clave):
        # "    hit@5   43/45  (95%)"  -> 95
        ms = re.findall(clave + r"\s+\d+/\d+\s+\((\d+)%\)", txt)
        return int(ms[-1]) if ms else None
    h5, h1 = pct("hit@5"), pct("hit@1")
    if h5 is None:
        return None
    return {"hit5": h5, "hit1": h1 or 0}


def lee_medidas():
    """El dict de medidas, con las unidades ya listas para el HUD."""
    diario = lee()[-MUESTRA:]
    if not diario:
        return {"n": 0}

    segs = [d["seg"] for d in diario if isinstance(d.get("seg"), (int, float)) and d["seg"] > 0]
    seg_cerebro = [d["seg"] for d in diario
                   if d.get("via") == CEREBRO and isinstance(d.get("seg"), (int, float))]
    seg_catalogo = [d["seg"] for d in diario
                    if d.get("via") == "catalogo" and isinstance(d.get("seg"), (int, float))]

    vias = {}
    for d in diario:
        vias[d.get("via", "?")] = vias.get(d.get("via", "?"), 0) + 1
    total = len(diario)

    def pct_via(v):
        return round(100 * vias.get(v, 0) / total) if total else 0

    # volumen: cuantas en las ultimas 24 h, y por hora las ultimas 12 para la traza
    ahora = datetime.now()
    hace24 = ahora - timedelta(hours=24)
    vol24 = 0
    porhora = [0] * 12
    for d in diario:
        try:
            t = datetime.fromisoformat(d.get("t", ""))
        except (ValueError, TypeError):
            continue
        if t >= hace24:
            vol24 += 1
        h = int((ahora - t).total_seconds() // 3600)
        if 0 <= h < 12:
            porhora[11 - h] += 1

    medidas = {
        "n": total,
        "lat_p50": round(_percentil(segs, 0.50), 2),
        "lat_p95": round(_percentil(segs, 0.95), 2),
        "lat_max": round(max(segs), 2) if segs else 0.0,
        "lat_cerebro": round(sum(seg_cerebro) / len(seg_cerebro), 2) if seg_cerebro else 0.0,
        "lat_catalogo": round(sum(seg_catalogo) / len(seg_catalogo), 2) if seg_catalogo else 0.0,
        "pct_cerebro": pct_via("cerebro"),
        "pct_catalogo": pct_via("catalogo"),
        "pct_ruido": pct_via("ruido"),
        "vol24": vol24,
        "porhora": porhora,
    }
    rag = _rag()
    if rag:
        medidas["rag"] = rag
    return medidas
