#!/usr/bin/env python3
"""
sysreport.py — Genera un reporte completo del sistema en JSON.
Usa jc para convertir la salida de comandos del sistema a JSON
estructurado. Ideal para diagnosticar, auditar o pasar a una IA.

Uso:
  python3 sysreport.py                    # Guarda en /tmp/sysreport.json
  python3 sysreport.py --stdout           # Imprime por stdout
  python3 sysreport.py --compact           # Sin pretty-print
  python3 sysreport.py --only discos       # Solo una sección

Dependencias:
  - Python 3.10+
  - jc (pip install jc)
  - jq (sudo apt install jq)
  - Los comandos del sistema: ps, df, systemctl, ss, free, uptime
"""

import argparse
import json
import subprocess
import sys
from datetime import datetime


# ─── Secciones del reporte ────────────────────────────────────────────────────

SECCIONES = {
    "procesos": (["ps", "aux"], "ps"),
    "discos": (["df", "-h"], "df"),
    "servicios": (["systemctl", "list-units", "--no-legend"], "systemctl"),
    "puertos": (["ss", "-tlnp"], "ss"),
    "memoria": (["free", "-h"], "free"),
    "uptime": (["uptime"], "uptime"),
}


def ejecutar_jc(comando: list, parser: str) -> list | dict:
    """Ejecuta un comando y lo parsea con jc."""
    try:
        out = subprocess.run(comando, capture_output=True, text=True, timeout=10)
        if out.returncode != 0:
            return {"error": f"Comando falló: {' '.join(comando)}"}
        # Parsear con jc
        jc_out = subprocess.run(
            ["jc", f"--{parser}"],
            input=out.stdout,
            capture_output=True,
            text=True,
            timeout=10,
        )
        if jc_out.returncode != 0:
            return {"error": f"jc falló para {parser}: {jc_out.stderr[:200]}"}
        return json.loads(jc_out.stdout)
    except subprocess.TimeoutExpired:
        return {"error": f"Timeout ejecutando {' '.join(comando)}"}
    except json.JSONDecodeError as e:
        return {"error": f"JSON inválido de jc --{parser}: {e}"}
    except FileNotFoundError:
        return {"error": f"jc no encontrado. Instala: pip install jc"}


def generar_reporte(secciones: list[str] | None = None) -> dict:
    """Genera el reporte del sistema."""
    incluir = secciones if secciones else list(SECCIONES.keys())

    reporte = {
        "fecha": datetime.now().isoformat(),
        "hostname": subprocess.run(
            ["hostname"], capture_output=True, text=True, timeout=5
        ).stdout.strip(),
    }

    for seccion in incluir:
        if seccion in SECCIONES:
            comando, parser = SECCIONES[seccion]
            reporte[seccion] = ejecutar_jc(comando, parser)

    return reporte


# ─── Main ─────────────────────────────────────────────────────────────────────

def main():
    parser = argparse.ArgumentParser(
        description="sysreport: reporte del sistema en JSON usando jc",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""\
Ejemplos:
  python3 sysreport.py                        # Guarda en /tmp/sysreport.json
  python3 sysreport.py --stdout                # Imprime por stdout
  python3 sysreport.py --only procesos discos  # Solo procesos y discos
  python3 sysreport.py --stdout | jq '.discos' # Filtrar con jq
        """,
    )
    parser.add_argument("--stdout", action="store_true", help="Imprimir por stdout en vez de guardar")
    parser.add_argument("--compact", action="store_true", help="Sin pretty-print (más pequeño)")
    parser.add_argument("--only", nargs="+", choices=list(SECCIONES.keys()),
                        help=f"Solo estas secciones: {', '.join(SECCIONES.keys())}")

    args = parser.parse_args()

    print("📡 Generando reporte del sistema...", file=sys.stderr)
    reporte = generar_reporte(args.only)

    indent = None if args.compact else 2

    if args.stdout:
        print(json.dumps(reporte, indent=indent, ensure_ascii=False))
    else:
        output_path = "/tmp/sysreport.json"
        with open(output_path, "w") as f:
            json.dump(reporte, f, indent=indent, ensure_ascii=False)
        print(f"✅ Reporte guardado en {output_path}", file=sys.stderr)
        print(f"📦 Tamaño: {len(json.dumps(reporte))} caracteres", file=sys.stderr)
        print(f"   Secciones: {', '.join(reporte.keys())}", file=sys.stderr)

        # Mostrar resumen rápido
        errores = [k for k, v in reporte.items() if isinstance(v, dict) and "error" in v]
        if errores:
            print(f"⚠️  Errores en: {', '.join(errores)}", file=sys.stderr)

        # Contar elementos por sección
        for k, v in reporte.items():
            if isinstance(v, list):
                print(f"   {k}: {len(v)} elementos", file=sys.stderr)


if __name__ == "__main__":
    main()