{ config, lib, pkgs, ... }:

with lib;

let
  knotKeys = let
    dir = ./keys;
    toKeyInfo = name: v:
      if v == "regular" || v == "symlink"
      then { path = dir + "/${name}"; inherit name; }
      else null;
  in filter (v: v != null) (mapAttrsToList toKeyInfo (builtins.readDir dir));
in {
  config = {
    services.unbound = {
      enable = true;
      resolveLocalQueries = false;
      stateDir = "/var/lib/unbound";
      localControlSocketPath = "/run/unbound/unbound.ctl";
      enableRootTrustAnchor = false;
      settings = {
        server = {
          interface = ["lo" "lan"];
          prefer-ip6 = true;
          access-control = ["0.0.0.0/0 allow" "::/0 allow"];
          root-hints = "${pkgs.dns-root-data}/root.hints";
          trust-anchor-file = "${pkgs.dns-root-data}/root.key";
          trust-anchor-signaling = false;
          ip-dscp = 20;

          num-threads = 12;
          so-reuseport = true;
          msg-cache-slabs = 16;
          rrset-cache-slabs = 16;
          infra-cache-slabs = 16;
          key-cache-slabs = 16;

          rrset-cache-size = "100m";
          msg-cache-size = "50m";
          outgoing-range = 8192;
          num-queries-per-thread = 4096;

          so-rcvbuf = "4m";
          so-sndbuf = "4m";

          # serve-expired = true;
          # serve-expired-ttl = 86400;
          # serve-expired-reply-ttl = 0;

          prefetch = true;
          prefetch-key = true;

          minimal-responses = false;

          extended-statistics = true;

          rrset-roundrobin = true;
          use-caps-for-id = true;

          do-not-query-localhost = false;
          local-zone = [
            "141.10.in-addr.arpa. transparent"
            "1.0.0.0.a.d.a.0.2.5.0.0.0.0.0.4.3.0.a.2.ip6.arpa. transparent"
            "yggdrasil. transparent"
          ];
          domain-insecure = [
            "141.10.in-addr.arpa."
            "1.0.0.0.a.d.a.0.2.5.0.0.0.0.0.4.3.0.a.2.ip6.arpa."
            "yggdrasil."
          ];
        };

        stub-zone = map (name: {
          inherit name;
          stub-addr = "127.0.0.1@5353";
          stub-first = true;
          stub-no-cache = true;
          stub-prime = false;
        }) ["yggdrasil." "arpa.in-addr.10.141." "1.0.0.0.a.d.a.0.2.5.0.0.0.0.0.4.3.0.a.2.ip6.arpa."];
      };
    };

    systemd.services.knot = {
      unitConfig.RequiresMountsFor = [ "/var/lib/knot" ];
      serviceConfig.LoadCredential = map ({name, ...}: "${name}.yaml:${config.sops.secrets.${name}.path}") knotKeys;
    };

    services.knot = {
      enable = true;
      keyFiles = map ({name, ...}: "/run/credentials/knot.service/${name}.yaml") knotKeys;
      extraConfig = ''
        server:
          listen: 127.0.0.1@5353
          listen: ::1@5353

          listen: 10.141.1.1@53
          listen: 10.141.2.1@53
          listen: 2a03:4000:52:ada:1:1::@53

        acl:
          - id: local_acl
            key: local_key
            action: update

        template:
          - id: local_zone
            storage: /var/lib/knot
            zonefile-sync: -1
            zonefile-load: difference-no-serial
            serial-policy: dateserial
            journal-content: all
            semantic-checks: on
            acl: [local_acl]

        zone:
          - domain: yggdrasil
            template: local_zone
            file: ${./zones/yggdrasil.soa}
          - domain: 141.10.in-addr.arpa
            template: local_zone
            file: ${./zones/arpa.in-addr.10.141.soa}
          - domain: 1.0.0.0.a.d.a.0.2.5.0.0.0.0.0.4.3.0.a.2.ip6.arpa
            template: local_zone
            file: ${./zones/arpa.ip6.2.a.0.3.4.0.0.0.0.0.5.2.0.a.d.a.0.0.0.1.soa}
      '';
    };

    sops.secrets = listToAttrs (map ({name, path}: nameValuePair name {
      format = "binary";
      owner = "knot";
      sopsFile = path;
    }) knotKeys);
  };
}