{ pkgs, lib, config, inputs, hosts, hostName, ... }:
let
  inherit (config.users) users groups;
  inherit (hosts.mermet.config.networking) domain;
in
{
  # TODO: nsupdate in the initrd
  systemd.services.nsupdate = {
    wantedBy = [ "multi-user.target" ];
    startAt = "*:0/5"; # every 5 min
    serviceConfig = {
      Type = "simple";
      LoadCredentialEncrypted = [
        "${hostName}.${domain}.tsig:${./nsupdate +"/${domain}/tsig.cred"}"
      ];
      ExecStart = pkgs.writeShellScript "nsupdate" ''
        set -eux
        publicIPv4=$(${pkgs.curl}/bin/curl -s4 https://whoami.sourcephile.fr/addr ||
          ${pkgs.curl}/bin/curl -s4L https://icanhazip.com || true)
        publicIPv6=$(${pkgs.curl}/bin/curl -s6L https://icanhazip.com || true)
        privateIPv4=$(${pkgs.miniupnpc}/bin/upnpc -s | sed -ne 's/^Local LAN ip address : //p')
        ${pkgs.knot-dns}/bin/knsupdate -k $CREDENTIALS_DIRECTORY/${hostName}.${domain}.tsig <<EOF
        server ns.${domain}
        zone ${domain}
        origin ${domain}
        update delete ${hostName} A
        ''${publicIPv4:+update add ${hostName} 300 A $publicIPv4}
        update delete ${hostName} AAAA
        ''${publicIPv6:+update add ${hostName} 300 AAAA $publicIPv6}
        update delete lan.${hostName} A
        ''${privateIPv4:+update add lan.${hostName} 300 A $privateIPv4}
        show
        send
        EOF
      '';
      Restart = "on-failure";
      RestartSec = "30s";
      DynamicUser = true;
      User = users."nsupdate".name;
    };
  };
  users.users."nsupdate" = {
    isSystemUser = true;
    group = groups."nsupdate".name;
  };
  users.groups."nsupdate" = { };
  networking.nftables.ruleset = ''
    table inet filter {
      set nsupdate-ssdp {
        type inet_service
        timeout 5s
      }
      chain input-net {
        udp dport @nsupdate-ssdp counter accept comment "SSDP answer"
      }
      chain output-net {
        skuid ${users.nsupdate.name} \
          ip daddr ${hosts.mermet._module.args.ipv4} \
          meta l4proto { udp, tcp } th dport domain \
          counter accept comment "nsupdate: DNS"
        skuid ${users.nsupdate.name} \
          tcp dport ssdp \
          counter accept \
          comment "SSDP automatic opening"
        skuid ${users.nsupdate.name} \
          ip daddr 239.255.255.250 udp dport ssdp \
          set add udp sport @nsupdate-ssdp \
          comment "SSDP automatic opening"
        skuid ${users.nsupdate.name} \
          ip daddr 239.255.255.250 udp dport ssdp \
          counter accept comment "SSDP"
      }
    }
  '' + lib.optionalString config.networking.enableIPv6 ''
    table inet filter {
      chain output-net {
        skuid ${users.nsupdate.name} \
          ip6 daddr { FF02::C, FF05::C, FF08::C, FF0E::C } \
          udp dport ssdp \
          set add udp sport @nsupdate-ssdp \
          comment "SSDP automatic opening"
        skuid ${users.nsupdate.name} \
          ip6 daddr { FF02::C, FF05::C, FF08::C, FF0E::C } \
          udp dport ssdp \
          counter accept comment "SSDP"
      }
    }
  '';
}