{ pkgs, lib, config, ... }:
let
  inherit (lib) types;
  inherit (config.services) knot;
  inherit (config.users) users groups;
in
{
  imports = [
    knot/autogeree.net.nix
    knot/sourcephile.fr.nix
  ];
  options.services.knot = {
    zones = lib.mkOption {
      default = { };
      type = types.attrsOf (types.submodule ({ ... }: {
        #config.domain = lib.mkDefault name;
        options = {
          conf = lib.mkOption {
            type = types.lines;
          };
          data = lib.mkOption {
            type = types.nullOr types.lines;
          };
        };
      }));
    };
  };
  config = {
    systemd.services.knot.serviceConfig.ExecStartPre =
      lib.mapAttrsToList
        (domain: { data, ... }: ''
          +${pkgs.coreutils}/bin/install -D -o ${users.knot.name} -g ${groups."knot".name} -m 700 \
           ${pkgs.writeText "${domain}.zone" data} \
           /var/lib/knot/zones/${domain}.zone
        '')
        knot.zones;
    /*
      systemd.services.knot.postStart = lib.mkAfter ''
      PATH="/run/current-system/sw/bin:$PATH"
      knotc zone-freeze ${domain}.
      while ! knotc zone-status ${domain}. +freeze | grep -q 'freeze: yes'; do sleep 1; done
      knotc zone-flush ${domain}.
      install -o knot -g knot -m 700 ${zone} /var/lib/knot/signed/${domain}.zone
      knotc zone-reload ${domain}.
      knotc zone-thaw ${domain}.
      '';
    */
    networking.nftables.ruleset = ''
      table inet filter {
        chain input-net {
          meta l4proto { udp, tcp } th dport domain counter accept comment "knot: DNS"
        }
        set output-net-knot-ipv4 { type ipv4_addr; }
        set output-net-knot-ipv6 { type ipv6_addr; }
        chain output-net {
          skuid ${users.knot.name} \
            meta l4proto { udp, tcp } th dport domain \
            ip daddr @output-net-knot-ipv4 \
            counter accept \
            comment "knot: DNS notify"
          skuid ${users.knot.name} \
            meta l4proto { udp, tcp } th dport domain \
            ip6 daddr @output-net-knot-ipv6 \
            counter accept \
            comment "knot: DNS notify"
        }
      }
    '';
    services.knot = {
      enable = true;
      extraArgs = [ "-v" ];
      # https://www.knot-dns.cz/docs/2.6/html/reference.html
      extraConfig = ''
        server :
          # Listen on localhost to allow only there
          # dynamic updates for ACME challenges.
          listen: 127.0.0.1@5353

        mod-rrl:
          - id: default
            rate-limit: 200
            slip: 2

        template:
          - id: default
            dnssec-signing: off
            # move databases below the state directory, because they need to be writable
            storage: /var/lib/knot/zones
            # Input-only zone files
            # https://www.knot-dns.cz/docs/2.8/html/operation.html#example-3
            # prevents modification of the zonefiles, since the zonefiles are immutable
            #zonefile-sync: -1
            zonefile-load: difference
            journal-content: changes
            global-module: mod-rrl/default

        database:
            journal-db: /var/lib/knot/journal
            kasp-db: /var/lib/knot/kasp
            timer-db: /var/lib/knot/timer

        log:
          - target: syslog
            any: info

        remote:
          - id: local_resolver
            address: 127.0.0.1@53

          - id: secondary_gandi
            address: 217.70.177.40@53

          - id: secondary_muarf
            address: 78.192.65.63@53

        submission:
          - id: dnssec_validating_resolver
            parent: local_resolver

        policy:
          - id: rsa
            single-type-signing: false
            ksk-shared: false
            algorithm: RSASHA256
            ksk-size: 4096
            zsk-size: 2048
            zsk-lifetime: 30d
            ksk-lifetime: 365d
            ksk-submission: dnssec_validating_resolver

          - id: ed25519
            single-type-signing: false
            ksk-shared: false
            algorithm: ED25519
            ksk-size: 256
            zsk-size: 256
            zsk-lifetime: 30d
            ksk-lifetime: 365d
            cds-cdnskey-publish: always
            ksk-submission: dnssec_validating_resolver

        acl:
          # DOC: https://docs.gandi.net/en/domain_names/advanced_users/secondary_nameserver.html
          - id: acl_gandi
            address: 217.70.177.40
            action: transfer

          - id: acl_muarf
            address: 78.192.65.63
            action: transfer

      '' + lib.concatStringsSep "\n" (lib.mapAttrsToList (_domain: { conf, ... }: conf) knot.zones);
    };
  };
}