#!/usr/bin/env python3
"""
Balse — calculadora de subredes
Proyecto educativo de Datapoint

Usa únicamente el módulo 'ipaddress' de la librería estándar de Python
(no necesita instalar nada). Recibe una IP con su máscara en notación
CIDR y muestra la información de la red: dirección de red, broadcast,
rango de hosts útiles y cuántos hosts caben.

Cómo usarlo:
    python3 subnet_calculator.py 192.168.1.10/24
    python3 subnet_calculator.py 10.0.5.0/26

Si no sabes qué es la notación CIDR (el "/24"), es la cantidad de bits
que se usan para identificar la red: /24 equivale a la máscara
255.255.255.0, la más común en redes domésticas.
"""

import argparse
import ipaddress
import sys


def analizar_red(entrada: str) -> None:
    try:
        interfaz = ipaddress.ip_interface(entrada)
    except ValueError as e:
        print(f"Error: '{entrada}' no es una dirección IP/CIDR válida.")
        print(f"Detalle: {e}")
        print("Formato esperado: IP/prefijo, por ejemplo 192.168.1.10/24")
        sys.exit(1)

    red = interfaz.network

    print("=" * 60)
    print(f"Análisis de {entrada}")
    print("=" * 60)
    print(f"IP ingresada:            {interfaz.ip}")
    print(f"Máscara de subred:       {red.netmask}  (/{red.prefixlen})")
    print(f"Dirección de red:        {red.network_address}")
    print(f"Dirección de broadcast:  {red.broadcast_address}")

    hosts = list(red.hosts())
    if hosts:
        print(f"Primer host útil:        {hosts[0]}")
        print(f"Último host útil:        {hosts[-1]}")
        print(f"Cantidad de hosts útiles:{len(hosts):>10}")
    else:
        print("Esta red es demasiado pequeña para tener hosts asignables")
        print("(por ejemplo, una /31 o /32 se usan para casos especiales).")

    print(f"Total de direcciones:    {red.num_addresses}")
    print(f"¿Es una red privada?     {'Sí' if red.is_private else 'No'}")


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="Calculadora de subredes educativa — Balse / Datapoint"
    )
    parser.add_argument(
        "red", nargs="?", help="IP con prefijo CIDR, ej: 192.168.1.10/24"
    )
    args = parser.parse_args()

    if args.red:
        analizar_red(args.red)
        pausar_al_salir()
        return

    # Sin argumentos: modo interactivo, más amigable para quien recién empieza.
    print("Calculadora de subredes — Balse")
    print("Escribe una IP con su prefijo, ej: 192.168.1.10/24")
    print("(Ctrl+C para salir)\n")
    while True:
        try:
            entrada = input("> ").strip()
        except (KeyboardInterrupt, EOFError):
            print()
            break
        if not entrada:
            continue
        analizar_red(entrada)
        print()


if __name__ == "__main__":
    main()
