{ pkgs, lib, config, hosts, ... }:
let
  inherit (builtins) hasAttr removeAttrs;
  inherit (config.security) gnupg;
  inherit (config.boot) initrd;
  iface = "wg-intra";
  wg = config.networking.wireguard.interfaces.${iface};
  wg-intra-hosts = import ../../../../networking/wireguard/wg-intra/hosts.nix;
  relay = wg-intra-hosts.mermet;
in
{
imports = [
  ../../../../networking/wireguard/wg-intra.nix
];
config = {
networking.wireguard.interfaces.${iface} = {
  privateKeyFile = gnupg.secrets."wireguard/${iface}/privateKey".path;
};
security.gnupg.secrets."wireguard/${iface}/privateKey" = {
/*
  systemdConfig.serviceConfig = {
    before     = [ "wireguard-${iface}.service" ];
    wantedBy   = [ "wireguard-${iface}.service" ];
    requiredBy = [ "wireguard-${iface}.service" ];
  };
*/
};
systemd.services."wireguard-${iface}" = {
  after    = [ gnupg.secrets."wireguard/${iface}/privateKey".service ];
  requires = [ gnupg.secrets."wireguard/${iface}/privateKey".service ];
  unitConfig.Upholds = [ "upnpc-${toString wg.listenPort}.service" ];
};
networking.nftables.ruleset = ''
  # Allow initiating connection to and from other peers
  add rule inet filter fw2net udp sport ${toString wg.listenPort} counter accept comment "WireGuard ${iface} output to peers"
  add rule inet filter net2fw udp dport ${toString wg.listenPort} counter accept comment "WireGuard ${iface} input from peers"

  # Hook ${iface} into relevant chains
  add rule inet filter input  iifname "${iface}" jump intra2fw
  add rule inet filter input  iifname "${iface}" log level warn prefix "intra2fw: " counter drop
  add rule inet filter output oifname "${iface}" jump fw2intra
  add rule inet filter output oifname "${iface}" log level warn prefix "fw2intra: " counter drop

  # ${iface} firewalling
  add rule inet filter fw2intra counter accept
  ${lib.concatMapStringsSep "\n" (ip: ''
    add rule inet filter intra2fw ip saddr ${ip} counter accept comment "relay"
  '') relay.ips}
  add rule inet filter forward iifname "${iface}" jump fwd-intra
'';
# Apparently required to get NAT reflection.
services.upnpc.redirections = [
  { description = "WireGuard"; externalPort = wg.listenPort; protocol = "UDP"; duration = 30 * 60;
    service.requiredBy = [ "wireguard-${iface}.service" ];
    service.before     = [ "wireguard-${iface}.service" ];
  }
];
boot.kernel.sysctl."net.ipv4.ip_forward" = 1;

# Open a wireguard tunnel to a relay
# in case the host is hosted behind a NAT and has no SSH port forwarding.
# This enables to send the disk password to the initrd, like that:
# ssh -J mermet.sourcephile.fr root@losurdo.wg -p 2222
boot.initrd.secrets."/root/initrd/${iface}.key" = "/root/initrd/${iface}.key";
/*
installer.ssh-nixos.script = ''
  # Send the wireguard key of the initrd
  gpg --decrypt '${gnupg.store}/wireguard/${iface}/privateKey.gpg' |
  ssh '${config.installer.ssh-nixos.target}' \
  install -D -m 400 -o root -g root /dev/stdin /root/initrd/${iface}.key
'';
*/
boot.initrd.kernelModules = [ "wireguard" ];
boot.initrd.extraUtilsCommands = ''
  #copy_bin_and_libs ${pkgs.wireguard-tools}/bin/wg
  cp -fpdv ${pkgs.wireguard-tools}/bin/.wg-wrapped $out/bin/wg
'';
boot.initrd.network.postCommands = ''
  ip link add dev ${iface} type wireguard
  ${lib.concatMapStringsSep "\n" (ip: ''
    ip address add ${ip} dev ${iface}
  '') wg.ips}
  wg set ${iface} private-key /root/initrd/${iface}.key \
     listen-port ${toString wg.listenPort}
  ip link set up dev ${iface}
  wg set ${iface} peer ${relay.peer.publicKey} \
     endpoint ${relay.ipv4}:${toString relay.listenPort} \
     allowed-ips ${relay.ipv4}/32 \
     persistent-keepalive 5
  ip route replace ${relay.ipv4}/32 dev ${iface} table main
'';
boot.initrd.postMountCommands = lib.mkIf initrd.network.flushBeforeStage2 ''
  ip link del dev ${iface}
'';
};
}