{ self, pkgs, lib, config, dns, ... }:
let
  secondary = "185.181.104.96";
  domain = config.networking.domain;
  # fetches all VgetVirtualHosts from the caddy config
  getVirtualHosts = hostname: map (name: builtins.substring 0 (builtins.stringLength name - (builtins.stringLength domain + 1)) name) (builtins.attrNames self.nixosConfigurations."${hostname}".config.services.caddy.virtualHosts);
  # generate CNAMES from caddy service to host
  genCNAMEs = hostname: lib.attrsets.genAttrs (getVirtualHosts hostname) (_label: { CNAME = [ "${hostname}.${domain}." ]; });
  # generate Bind config to allow dynamic updates
  genKeyGrants = hostname: builtins.foldl' (x: y: x + "grant caddy name _acme-challenge." + y + ".${domain} txt;\n") "" (lib.lists.remove ":2018" (getVirtualHosts hostname));
  zonefile = with dns.lib.combinators; pkgs.writeText "rfive.de.zone.txt" (dns.lib.toString domain {
    TTL = 3600;
    SOA =
      let
        modulo = number: mod: (number - ((number / mod) * mod));
      in
      {
        nameServer = "ns.rfive.de.";
        adminEmail = "hostmaster@rfive.de";
        serial = lib.strings.toInt (builtins.substring 0 8 self.sourceInfo.lastModifiedDate + toString ((modulo self.sourceInfo.lastModified 86400) / 864));
        # serial = 2025051143;
        refresh = 10800;
        retry = 3600;
        expire = 604800;
        minimum = 3600;
      };
    NS = [
      "ns.inwx.de."
      "ns2.inwx.de."
      "ns3.inxw.eu."
    ];
    A = [ "23.88.121.184" ];
    AAAA = [ "2a01:4f8:c012:49de::1" ];

    CAA = letsEncrypt "ca@rfive.de";

    MX = [{ preference = 1; exchange = "mail.rfive.de."; }];

    TXT = [
      (spf.soft [ "mx" ])
    ];


    subdomains =
      lib.attrsets.mergeAttrsList [
        rec {
          nuc = {
            A = [ "141.30.227.6" ];
          };
          avm = {
            A = [ "141.30.30.20" ];
          };
          falkenstein = {
            A = [ "23.88.121.184" ];
            AAAA = [ "2a01:4f8:c012:49de::1" ];
          };
          ns = falkenstein;
          mail = falkenstein;
          _dmarc.TXT = [ "v=DMARC1; p=none; adkim=s; fo=1; rua=mailto:dmarc@rfive.de; ruf=mailto:dmarc@rfive.de" ];
          _domainkey.subdomains.rspamd.TXT = [ "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDoirUMubro4nlmY6a8JMwK9QB2agAXiJzexDU/7ba6KCggONfoSTfUHlrM/XeM1GG/9oKpngApxDPP97adJuxc8/EELyo4HjTyYD8GBFZhg0AN7V8IPaJ1o5k6dGDk8ZLh41ZCnlAVWkhVSKs5pYtzkrlJIfUSzyuoe8nuFsVe3QIDAQAB" ];
        }
        (builtins.removeAttrs (genCNAMEs "nuc") ([ ":2018" ] ++ (builtins.filter (host: lib.strings.hasInfix "vpn" host) (getVirtualHosts "nuc"))))
        (builtins.removeAttrs (genCNAMEs "falkenstein") ([ ":2018" "mail" "rfive.de" ] ++ (builtins.filter (host: lib.strings.hasInfix "vpn" host) (getVirtualHosts "nuc"))))
        # (mergeRecords [
        #   (builtins.removeAttrs (genCNAMEs "nuc") ([ ":2018" ] ++ (builtins.filter (host: lib.strings.hasInfix "vpn" host) (getVirtualHosts "nuc"))))
        #   (builtins.removeAttrs (genACMECNAMEs "nuc") ([ ":2018" ]))
        # ])
        # (mergeRecords [
        #   (builtins.removeAttrs (genCNAMEs "falkenstein") ([ ":2018" "mail" ]))
        #   (builtins.removeAttrs (genACMECNAMEs "falkenstein") ([ ":2018" "mail" ]))
        # ])
        # (builtins.removeAttrs (genACMECNAMEs "fujitsu") ([ ":2018" ]))
      ];
  });
in
{
  age.secrets.acme-dns = {
    file = ../../../../secrets/falkenstein/acme-dns.age;
    owner = "named";
  };
  services.bind = rec {
    enable = true;
    directory = "/var/lib/bind";
    extraConfig = ''
      dnssec-policy "split-keys" {
        keys {
          ksk lifetime unlimited algorithm ecdsap256sha256;
          zsk lifetime 60d algorithm ecdsap256sha256;
        };
        publish-safety 1d;
        retire-safety 1d;
      };
      include "${config.age.secrets.acme-dns.path}";
    '';
    zones = {
      "rfive.de" = {
        master = true;
        slaves = [
          secondary
        ];
        extraConfig = ''
          also-notify {${secondary};};
          dnssec-policy split-keys;
          inline-signing yes;
          serial-update-method date;
          update-policy {
            grant caddy name _acme-challenge.cinema.vpn.rfive.de. txt;
            ${genKeyGrants "nuc"}
            ${genKeyGrants "falkenstein"}
            ${genKeyGrants "fujitsu"}
          };
        '';
        file = "${directory}/rfive.de.zone.txt";
      };
    };
  };
  systemd.services.bind-zonefile = {
    script = ''      
      # copy the file manually to its destination since signing requires a writable directory
      ${pkgs.coreutils}/bin/cp ${zonefile} ${config.services.bind.directory}/rfive.de.zone.txt
      ${pkgs.coreutils}/bin/chown named:named ${config.services.bind.directory}/rfive.de.zone.txt
    '';
  };
  systemd.services.bind = {
    after = [ "bind-zonefile.service" ];
    requires = [ "bind-zonefile.service" ];
  };
  networking.firewall.extraInputRules = ''
    ip saddr ${secondary}/32 tcp dport 53 accept comment "Allow DNS AXFR access from INWX Servers"
    ip saddr ${secondary}/32 udp dport 53 accept comment "Allow DNS access from INWX Servers"
  '';
  environment.systemPackages = with pkgs; [ dig.out ];
}