"""Diagnostico: ¿este servidor aguanta el sistema?

Subelo al hosting y correlo por SSH:
    python3 diagnostico_hosting.py

No instala nada ni toca archivos. Solo mira y reporta.
Te dice que parte funcionaria (panel) y cual no (robot de Canva).
"""
from __future__ import annotations

import os
import platform
import shutil
import subprocess
import sys

VERDE, ROJO, AMBAR, GRIS, FIN = "\033[92m", "\033[91m", "\033[93m", "\033[90m", "\033[0m"
if os.name == "nt" or not sys.stdout.isatty():
    VERDE = ROJO = AMBAR = GRIS = FIN = ""

fallos_robot: list[str] = []
fallos_panel: list[str] = []


def linea(ok: bool | None, titulo: str, detalle: str = "") -> None:
    marca = f"{VERDE}[ OK ]{FIN}" if ok else (f"{ROJO}[FALLA]{FIN}" if ok is False
                                              else f"{AMBAR}[ ?? ]{FIN}")
    print(f"  {marca} {titulo}")
    if detalle:
        print(f"         {GRIS}{detalle}{FIN}")


def mem_total_mb() -> int | None:
    try:
        with open("/proc/meminfo") as f:
            for l in f:
                if l.startswith("MemTotal:"):
                    return int(l.split()[1]) // 1024
    except Exception:  # noqa: BLE001
        pass
    return None


def mem_libre_mb() -> int | None:
    try:
        with open("/proc/meminfo") as f:
            datos = {l.split(":")[0]: int(l.split()[1]) for l in f if ":" in l}
        return datos.get("MemAvailable", 0) // 1024
    except Exception:  # noqa: BLE001
        return None


def hay_lib(nombre: str) -> bool:
    """Busca una libreria compartida por las rutas tipicas."""
    rutas = ["/lib", "/lib64", "/usr/lib", "/usr/lib64",
             "/usr/lib/x86_64-linux-gnu", "/usr/local/lib"]
    for base in rutas:
        if not os.path.isdir(base):
            continue
        try:
            for f in os.listdir(base):
                if f.startswith(nombre):
                    return True
        except PermissionError:
            continue
    try:
        s = subprocess.run(["ldconfig", "-p"], capture_output=True, text=True, timeout=15)
        return nombre in s.stdout
    except Exception:  # noqa: BLE001
        return False


print("\n" + "=" * 62)
print("  ¿ESTE SERVIDOR AGUANTA EL SISTEMA?")
print("=" * 62)
print(f"  {GRIS}{platform.platform()}{FIN}\n")

# ---------------------------------------------------------------- PANEL
print("PARTE 1 — El panel web (tabla, finanzas, edicion)\n")

v = sys.version_info
ok = v >= (3, 10)
linea(ok, f"Python {v.major}.{v.minor}.{v.micro}",
      "" if ok else "Hace falta 3.10 o mas nuevo")
if not ok:
    fallos_panel.append(f"Python {v.major}.{v.minor} es muy viejo")

pip = shutil.which("pip3") or shutil.which("pip")
linea(bool(pip), "pip disponible", pip or "No encontrado: no podras instalar dependencias")
if not pip:
    fallos_panel.append("Sin pip")

try:
    import venv  # noqa: F401
    linea(True, "Puede crear entornos virtuales (venv)")
except ImportError:
    linea(False, "Sin modulo venv")
    fallos_panel.append("Sin venv")

escribible = os.access(".", os.W_OK)
linea(escribible, "Puede escribir en el directorio actual",
      "Los CSV de datos necesitan escritura" if not escribible else "")
if not escribible:
    fallos_panel.append("Directorio de solo lectura")

# ---------------------------------------------------------------- ROBOT
print("\nPARTE 2 — El robot de Canva (auditar, invitar, sacar)\n")

ssh = bool(os.environ.get("SSH_CONNECTION") or os.environ.get("SSH_TTY"))
linea(ssh or None, "Estas por SSH" if ssh else "No detecto SSH",
      "" if ssh else "Si corres esto desde un panel web y no por SSH, "
                     "probablemente no puedas instalar Chromium")
if not ssh:
    fallos_robot.append("Sin SSH confirmado")

tot, libre = mem_total_mb(), mem_libre_mb()
if tot:
    ok = tot >= 2000
    linea(ok, f"RAM total: {tot} MB (libre: {libre} MB)",
          "Chromium come ~1 GB. Con menos de 2 GB se muere" if not ok else "")
    if not ok:
        fallos_robot.append(f"Solo {tot} MB de RAM")
    if libre is not None and libre < 900:
        linea(False, f"RAM libre insuficiente: {libre} MB", "Necesitas ~900 MB libres")
        fallos_robot.append(f"Solo {libre} MB libres ahora")
else:
    linea(None, "No pude leer la RAM", "Hosting compartido suele ocultarla")

libs = {
    "libnss3": "certificados",
    "libatk-1.0": "accesibilidad",
    "libgbm": "render grafico",
    "libxkbcommon": "teclado",
    "libpango-1.0": "texto",
    "libasound": "audio",
}
faltan = [f"{n} ({p})" for n, p in libs.items() if not hay_lib(n)]
if faltan:
    linea(False, f"Faltan {len(faltan)} de {len(libs)} librerias que Chromium exige",
          ", ".join(faltan))
    fallos_robot.append(f"Faltan librerias: {', '.join(n.split()[0] for n in faltan)}")
else:
    linea(True, "Estan las librerias que Chromium exige")

try:
    n = len(os.sched_getaffinity(0))
except AttributeError:
    n = os.cpu_count() or 0
linea(n >= 2, f"CPUs disponibles: {n}", "Con 1 CPU va muy lento" if n < 2 else "")

try:
    s = subprocess.run(["bash", "-c", "ulimit -u"], capture_output=True, text=True, timeout=10)
    lim = s.stdout.strip()
    if lim.isdigit():
        ok = int(lim) >= 100
        linea(ok, f"Limite de procesos: {lim}",
              "Chromium abre decenas de procesos hijos" if not ok else "")
        if not ok:
            fallos_robot.append(f"Limite de procesos muy bajo ({lim})")
except Exception:  # noqa: BLE001
    linea(None, "No pude leer el limite de procesos")

libre_disco = shutil.disk_usage(".").free // (1024 ** 2)
ok = libre_disco >= 600
linea(ok, f"Disco libre: {libre_disco} MB", "Chromium ocupa ~450 MB" if not ok else "")
if not ok:
    fallos_robot.append(f"Solo {libre_disco} MB de disco")

# ---------------------------------------------------------------- VEREDICTO
print("\n" + "=" * 62)
print("  VEREDICTO")
print("=" * 62 + "\n")

if not fallos_panel:
    print(f"  {VERDE}El PANEL si corre aqui.{FIN}")
else:
    print(f"  {ROJO}El PANEL no corre aqui:{FIN}")
    for f in fallos_panel:
        print(f"     - {f}")

print()
if not fallos_robot:
    print(f"  {VERDE}El ROBOT tambien corre. Puedes montar todo aqui.{FIN}")
else:
    print(f"  {ROJO}El ROBOT no corre aqui:{FIN}")
    for f in fallos_robot:
        print(f"     - {f}")
    print(f"\n  {AMBAR}Sin robot no hay auditar, invitar ni sacar,{FIN}")
    print(f"  {AMBAR}que es para lo que existe el sistema.{FIN}")
    print(f"\n  Alternativa: un VPS de 2 vCPU y 4 GB (~$6-12/mes).")

print(f"\n  {AMBAR}Recuerda:{FIN} el panel no tiene contraseña. Antes de subirlo")
print("  a cualquier servidor con IP publica hay que ponerle login,")
print("  o quedan expuestos los correos y fechas de pago de tus clientes.\n")
