#!/usr/bin/env python3
"""
Balse — ping y traceroute
Proyecto educativo de Datapoint

Este script NO reimplementa ping/traceroute desde cero: llama a los
comandos que ya trae tu sistema operativo (ping, tracert/traceroute) y
te muestra el resultado de forma más ordenada. Se hace así a propósito:
enviar paquetes ICMP en crudo requiere permisos de administrador en la
mayoría de los sistemas, y usar el comando del sistema evita eso.

Cómo usarlo:
    python3 ping_traceroute.py datapoint.cl
    python3 ping_traceroute.py 8.8.8.8 --solo-ping
    python3 ping_traceroute.py datapoint.cl --solo-traceroute

Requiere: Python 3.7 o más nuevo. No necesita instalar nada más.
"""

import argparse
import platform
import subprocess
import sys


def es_windows() -> bool:
    return platform.system().lower() == "windows"


def ejecutar(comando: list[str]) -> None:
    """Corre un comando del sistema y muestra su salida en vivo, línea por línea."""
    print(f"$ {' '.join(comando)}\n")
    try:
        proceso = subprocess.Popen(
            comando, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True
        )
        for linea in proceso.stdout:
            print(linea, end="")
        proceso.wait()
    except FileNotFoundError:
        print(f"No se encontró el comando '{comando[0]}' en tu sistema.")
    except KeyboardInterrupt:
        print("\nInterrumpido por el usuario.")


def hacer_ping(host: str) -> None:
    print("=" * 60)
    print(f"PING a {host}")
    print("=" * 60)
    if es_windows():
        comando = ["ping", "-n", "4", host]
    else:
        comando = ["ping", "-c", "4", host]
    ejecutar(comando)


def hacer_traceroute(host: str) -> None:
    print("\n" + "=" * 60)
    print(f"TRACEROUTE a {host} (salto por salto hasta llegar)")
    print("=" * 60)
    if es_windows():
        comando = ["tracert", host]
    else:
        # macOS y Linux traen 'traceroute'. Si no está, se avisa igual.
        comando = ["traceroute", host]
    ejecutar(comando)


def pausar_al_salir() -> None:
    """Evita que la ventana se cierre de golpe si el script se abrió con doble clic."""
    try:
        input("\nPresiona Enter para cerrar...")
    except (EOFError, KeyboardInterrupt):
        pass


def main() -> None:
    parser = argparse.ArgumentParser(
        description="Ping y traceroute educativo — Balse / Datapoint"
    )
    parser.add_argument(
        "host", nargs="?", default=None,
        help="Dominio o IP a probar, ej: datapoint.cl"
    )
    parser.add_argument(
        "--solo-ping", action="store_true", help="Ejecutar solo el ping"
    )
    parser.add_argument(
        "--solo-traceroute", action="store_true", help="Ejecutar solo el traceroute"
    )
    args = parser.parse_args()

    host = args.host
    if not host:
        print("Balse — ping y traceroute\n")
        host = input("¿Qué dominio o IP quieres probar? (ej: datapoint.cl): ").strip()
        if not host:
            print("No escribiste nada, saliendo.")
            pausar_al_salir()
            return

    if args.solo_ping:
        hacer_ping(host)
    elif args.solo_traceroute:
        hacer_traceroute(host)
    else:
        hacer_ping(host)
        hacer_traceroute(host)

    print(
        "\nTip: en el traceroute, cada línea es un 'salto' — un router distinto\n"
        "por el que pasó tu conexión antes de llegar al destino. Compara cuántos\n"
        "saltos hay hacia distintos sitios (uno local vs uno en otro continente)."
    )
    pausar_al_salir()


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\nInterrumpido por el usuario.")
        pausar_al_salir()
