import sys
import time
import psutil

INTERVAL = 2  # seconds between samples


def to_mbps(bytes_per_sec):
    return bytes_per_sec * 8 / 1_000_000


def get_target_interface():
    """Select user-provided interface or auto-detect the active physical NIC."""
    if len(sys.argv) > 1:
        chosen = sys.argv[1]
        available = psutil.net_io_counters(pernic=True)
        if chosen in available:
            return chosen
        print(f"Error: Interface '{chosen}' not found. Available: {list(available.keys())}")
        sys.exit(1)

    stats = psutil.net_if_stats()
    addrs = psutil.net_if_addrs()
    io_counters = psutil.net_io_counters(pernic=True)

    ignore_prefixes = ("lo", "Loopback", "docker", "veth", "br-", "virbr", "vmnet")

    for nic, nic_stats in stats.items():
        if any(nic.startswith(prefix) for prefix in ignore_prefixes):
            continue
        if not nic_stats.isup:
            continue

        # Check if interface has an IPv4 address and active traffic
        has_ipv4 = any(addr.family.name == "AF_INET" for addr in addrs.get(nic, []))
        if has_ipv4 and nic in io_counters:
            return nic

    # Fallback to the first non-loopback interface with I/O counters
    for nic in io_counters:
        if not any(nic.startswith(prefix) for prefix in ignore_prefixes):
            return nic

    return None


def main():
    target_nic = get_target_interface()

    if not target_nic:
        print("Error: Could not identify an active physical network interface.")
        print("Available interfaces:", list(psutil.net_io_counters(pernic=True).keys()))
        return

    print(f"Monitoring interface: [{target_nic}] (Loopback & internal traffic excluded)")
    print("Press Ctrl+C to stop and view the summary.\n")
    print(f"{'time':<10} {'down (Mbps)':<14} {'up (Mbps)':<12}")

    down_samples = []
    up_samples = []

    prev_counters = psutil.net_io_counters(pernic=True)[target_nic]
    prev_time = time.time()

    try:
        while True:
            time.sleep(INTERVAL)
            all_counters = psutil.net_io_counters(pernic=True)
            if target_nic not in all_counters:
                print(f"\nWarning: Interface '{target_nic}' disappeared.")
                break

            now_counters = all_counters[target_nic]
            now_time = time.time()
            elapsed = max(now_time - prev_time, 0.001)

            down_bps = (now_counters.bytes_recv - prev_counters.bytes_recv) / elapsed
            up_bps = (now_counters.bytes_sent - prev_counters.bytes_sent) / elapsed

            down_mbps = to_mbps(down_bps)
            up_mbps = to_mbps(up_bps)

            down_samples.append(down_mbps)
            up_samples.append(up_mbps)

            print(f"{time.strftime('%H:%M:%S'):<10} {down_mbps:<14.2f} {up_mbps:<12.2f}")

            prev_counters, prev_time = now_counters, now_time

    except KeyboardInterrupt:
        print(f"\n\n--- Summary for [{target_nic}] ---")
        if not down_samples:
            print("No samples collected.")
            return

        print(f"Samples collected: {len(down_samples)} over ~{len(down_samples) * INTERVAL}s")
        print(f"Download: avg {sum(down_samples)/len(down_samples):.2f} Mbps | "
              f"peak {max(down_samples):.2f} Mbps")
        print(f"Upload:   avg {sum(up_samples)/len(up_samples):.2f} Mbps | "
              f"peak {max(up_samples):.2f} Mbps")


if __name__ == "__main__":
    main()