{ config, pkgs, lib, hostName, ... }:
with lib;
{
  imports = [
    networking/nftables.nix
  ];

  boot.kernel.sysctl = {
    # Improve MTU detection
    # This can thaw TCP connections stalled by a host
    # requiring a lower MTU along the path,
    # though it would do so after a little delay
    # so it's better to set a low MTU when possible.
    "net/ipv4/tcp_mtu_probing" = 1;

    # Use TCP BBR to significantly increase throughput
    # and reduce latency for connections.
    "net/ipv4/tcp_congestion_control" = mkDefault "bbr";

    # BBR must be used with the fq or fq_codel qdisc with pacing enabled,
    # since pacing is integral to the BBR design and implementation.
    # BBR without pacing would not function properly,
    # and may incur unnecessary high packet loss rates.
    #
    # See https://github.com/systemd/systemd/issues/9725#issuecomment-412287161
    # See https://github.com/systemd/systemd/issues/9725#issuecomment-413796842
    # > The best all-round general purpose default for linux remains fq_codel.
    "net/core/default_qdisc" = mkDefault "fq_codel";

    # Request Explicit Congestion Notification (ECN)
    # only for incoming connections (not outgoing).
    # See https://github.com/systemd/systemd/issues/9748#issuecomment-1261352478
    # > My answer to the ECN situation remains - turn it on
    # > - see if it works - don't inflict your decision on others.
    # > $ sysctl -w net.ipv4.tcp_ecn=1
    # > $ flent -H flent-newark.bufferbloat.net -t 'now tv hub ecn' \
    # >         --te=download_streams=1 --socket-stats tcp_ndown # try 1,4,16
    # > $ sysctl -w net.ipv4.tcp_ecn=2
    # > $ flent -H flent-newark.bufferbloat.net -t 'now tv hub noecn' \
    # >         --te=download_streams=1 --socket-stats tcp_ndown # try 1,4,16
    # > you can then use flent-gui *.flent.gz to generate a variety of plots,
    # > especially comparison plots.
    "net/ipv4/tcp_ecn" = mkDefault 2;
  };

  networking = {
    inherit hostName;
    domain = mkDefault "sp";
    #search = [ "sourcephile.fr" ];
    firewall = {
      enable = mkDefault true;
      allowPing = mkDefault true;
    };
    networkmanager = {
      #dhcp = "dhcpcd";
      logLevel = mkDefault "INFO";
      wifi = {
        #backend = "iwd";
        #backend = "wpa_supplicant";
        powersave = mkDefault false;
      };
    };
    usePredictableInterfaceNames = true;
  };

  programs.mtr.enable = true;
  programs.traceroute.enable = mkDefault true;
  programs.usbtop.enable = true;

  services.openssh.enable = mkDefault true;

  # Fix https://github.com/NixOS/nixpkgs/issues/180175 by removing -s (aka. --wait-for-startup)
  systemd.services.NetworkManager-wait-online = lib.mkIf config.networking.networkmanager.enable {
    unitConfig.StartLimitIntervalSec = 0;
    serviceConfig = {
      ExecStart = [ "" "${pkgs.networkmanager}/bin/nm-online -q" ];
      Restart = "on-failure";
      RestartSec = 1;
    };
  };
  environment.etc."NetworkManager/dispatcher.d/congctl" = {
    mode = "700";
    source = pkgs.writeShellScript "congctl" ''
      case $NM_DISPATCHER_ACTION in
        up)
          case $DEVICE_IP_IFACE in
            # WLAN or WWAN
            # https://en.wikipedia.org/wiki/TCP_congestion_control#TCP_Westwood+
            wl*|ww*)
              ip route show dev $DEVICE_IP_IFACE |
              while read -r route; do
                ip route change $route dev $DEVICE_IP_IFACE congctl westwood
              done
            ;;
          esac
        ;;
      esac
    '';
  };

  # The notion of "online" is a broken concept
  #systemd.services.NetworkManager-wait-online.enable = false;
  #systemd.network.wait-online.enable = false;

  # Do not take down the network for too long when upgrading,
  # This also prevents failures of services that are restarted instead of stopped.
  # It will use `systemctl restart` rather than stopping it with `systemctl stop`
  # followed by a delayed `systemctl start`.
  systemd.services.systemd-networkd.stopIfChanged = false;

  # Services that are only restarted might be not able
  # to resolve when resolved is stopped before.
  systemd.services.systemd-resolved.stopIfChanged = false;
}