# -*- coding: utf-8 -*-
"""
Parche 2: navegacion de !onts en Mattermost, por numeros en vez de botones.

    !onts        -> lista de OLTs numeradas
    !onts 2      -> puertos PON de esa OLT, numerados
    !onts 2 5    -> detalle de ese PON

El detalle NO se reescribe: se sintetiza el mismo callback que generan los
botones de Telegram y lo atiende handle_callback tal cual. Para eso edit()
pasa a publicar un mensaje nuevo cuando el destino es Mattermost.

Telegram no se toca: sigue con sus botones.
Idempotente: si ya esta aplicado, avisa y no toca nada.
"""
from __future__ import print_function

import io
import sys

RUTA = "/home/gor/snmp/smartolt/bot.py"
if len(sys.argv) > 1:
    RUTA = sys.argv[1]

s = io.open(RUTA, encoding="utf-8").read()

if "_onts_texto" in s:
    raise SystemExit("El parche ya estaba aplicado. No se toca nada.")

# --- 1. edit() publica en vez de no hacer nada -----------------------
EDIT_VIEJO = '''    # Mattermost no tiene el concepto de editar un mensaje por id como
    # Telegram; los comandos que editan simplemente no editan alli.
    if chat == MM_CHAT:
        return
'''
EDIT_NUEVO = '''    # Mattermost no edita por id: se publica un mensaje nuevo. Asi la
    # navegacion de los callbacks (OLT -> PON -> detalle) sirve igual
    # sin reescribir nada de esa logica.
    if chat == MM_CHAT:
        if mattermost:
            mattermost.publicar(text)
        return
'''
if EDIT_VIEJO not in s:
    raise SystemExit("No encuentro el guard de edit(). Aborto.")
s = s.replace(EDIT_VIEJO, EDIT_NUEVO, 1)

# --- 2. handle_callback tolera callbacks sinteticos ------------------
CB_VIEJO = '''def handle_callback(cq):
    answer(cq["id"])
    chat   = cq["message"]["chat"]["id"]
    if not autorizado(chat):
        return
'''
CB_NUEVO = '''def handle_callback(cq):
    # Los comandos de Mattermost sintetizan un callback sin id: no hay
    # nada que responderle a Telegram.
    if cq.get("id"):
        answer(cq["id"])
    chat   = cq["message"]["chat"]["id"]
    # En Mattermost la autorizacion la da estar en el canal, no el chat_id.
    if chat != MM_CHAT and not autorizado(chat):
        return
'''
if CB_VIEJO not in s:
    raise SystemExit("handle_callback no coincide. Aborto.")
s = s.replace(CB_VIEJO, CB_NUEVO, 1)

# --- 3. navegacion por numeros ---------------------------------------
ANCLA = '''def comando_mattermost(texto, autor_id, post_id):'''
if ANCLA not in s:
    raise SystemExit("No encuentro comando_mattermost. Aborto.")

FUNCION = r'''def _onts_texto(args):
    """
    Equivalente en texto de los botones de /onts. Devuelve el texto a
    publicar, o None si ya lo ha publicado handle_callback.

    El orden de las listas es el mismo que el de los botones, asi que el
    numero que se teclea corresponde siempre a la misma OLT o PON
    mientras el cache no cambie.
    """
    onus = get_onus_cached()
    if not onus:
        return "⏳ Caché no disponible aún."

    olts = sorted(set(o.get("olt_name", "") for o in onus if o.get("olt_name")))
    if not olts:
        return "No hay OLTs en el caché."

    # Nivel 0: las OLTs
    if not args:
        lineas = ["📡 **OLTs disponibles** — datos de hace {} min\n".format(
            edad_cache() // 60)]
        for i, olt in enumerate(olts, 1):
            n = sum(1 for o in onus if o.get("olt_name") == olt)
            lineas.append("`{:>2}` · {} — {} ONUs".format(i, olt, n))
        lineas.append("\nEscribe `!onts <numero>` para ver sus puertos PON")
        return "\n".join(lineas)

    try:
        i_olt = int(args[0])
        olt = olts[i_olt - 1]
        if i_olt < 1:
            raise IndexError
    except (ValueError, IndexError):
        return "Numero de OLT no valido. Escribe `!onts` para ver la lista."

    pons = analizar_pons([o for o in onus if o.get("olt_name") == olt])
    if not pons:
        return "Sin ONUs en `{}`.".format(olt)
    ordenados = sorted(pons.values(),
                       key=lambda x: (x["board"],
                                      int(x["port"]) if str(x["port"]).isdigit() else 0))

    # Nivel 1: los puertos PON de esa OLT
    if len(args) == 1:
        lineas = ["📡 **{}** — puertos PON\n".format(olt)]
        for j, st in enumerate(ordenados, 1):
            pct = calcular_pct_los(st)
            icono = "🚨" if pct >= LOS_PCT_UMBRAL else ("⚠️" if st["los"] > 0 else "🟢")
            lineas.append("`{:>2}` {} B{}/PON{} — {}✅ {}⚠️ {}🔴 ({} total)".format(
                j, icono, st["board"], st["port"],
                st["online"], st["los"], st["offline"], st["total"]))
        lineas.append("\nEscribe `!onts {} <numero>` para el detalle".format(i_olt))
        return "\n".join(lineas)

    # Nivel 2: el detalle. Se reutiliza el mismo camino que los botones.
    try:
        n_pon = int(args[1])
        if n_pon < 1:
            raise IndexError
        st = ordenados[n_pon - 1]
    except (ValueError, IndexError):
        return "Numero de PON no valido. Escribe `!onts {}` para ver la lista.".format(
            args[0])

    handle_callback({
        "id": None,
        "message": {"chat": {"id": MM_CHAT}, "message_id": 0},
        "data": "PON:{}:{}:{}".format(olt, st["board"], st["port"]),
    })
    return None


'''
s = s.replace(ANCLA, FUNCION + ANCLA, 1)

# --- 4. despacho con argumentos --------------------------------------
DESPACHO_VIEJO = '''    orden = texto.strip().split()[0].lower()
    tabla = {'''
DESPACHO_NUEVO = '''    partes = texto.strip().split()
    orden = partes[0].lower()

    # !onts navega por numeros porque los botones de Telegram no existen
    # en Mattermost: !onts / !onts 2 / !onts 2 5
    if orden == "!onts":
        return _onts_texto(partes[1:])

    tabla = {'''
if DESPACHO_VIEJO not in s:
    raise SystemExit("El despacho de comando_mattermost no coincide. Aborto.")
s = s.replace(DESPACHO_VIEJO, DESPACHO_NUEVO, 1)

io.open(RUTA, "w", encoding="utf-8", newline="\n").write(s)
print("Parche 2 aplicado sobre %s" % RUTA)
