{ lib, config, options, pkgs, modulesPath, ... }:
with lib;
let
  cfg = config.yoda.netcup-dns;

  my-python-packages = ps: with ps; [
    # netcup-dns is not (yet) packaged, thus we build it from PyPI
    (
      buildPythonPackage rec {
        pname = "netcup-dns";
        # Important: When updating the version number, adjust the Git revision below accordingly!
        version = "0.2.4";
        # https://nixos.wiki/wiki/Packaging/Python#Fix_Missing_setup.py
        format = "pyproject";
        src = builtins.fetchGit {
          url = "https://codeberg.org/privacy1st/netcup-dns";
          rev = "7981656c5b65ac37ab2fd0e9bc65bd8cedd5ed79";
        };
        propagatedBuildInputs = [
          # Dependencies
          pkgs.python3Packages.requests
          pkgs.python3Packages.nc-dnsapi
          # Build dependencies
          setuptools
          build
          twine
        ];
      }
    )
  ];
in
{
  options = {
    yoda.netcup-dns = mkOption {
      type = types.path;
      example = ./secrets/netcup-dns.json;
      description = ''
        Path to JSON configuration file for netcup-dns.
      '';
    };
  };

  config = {
    # Install netcup-dns Python packages.
    environment.systemPackages = [
      (pkgs.python3.withPackages my-python-packages)
    ];

    # Configure netcup-dns.
    # This creates file `/etc/netcup-dns/netcup-dns-95191.json`.
    # Update A and AAA entry of domains p1st.de, privacy1st.de, biketripplanner.de
    deployment.keys."netcup-dns-95191.json" = {
      keyFile = cfg;
      destDir = "/etc/netcup-dns";
      user = "netcup-dns";
      group = "netcup-dns";
    };
    # Create netcup-dns daemon user.
    users.users."netcup-dns" = {
      isSystemUser = true;
      group = "netcup-dns";
      description = "netcup-dns daemon";
    };
    users.groups."netcup-dns" = {};
    # Create netcup-dns timer.
    systemd.timers."netcup-dns" = {
      wantedBy = [ "timers.target" ];
      partOf = [ "netcup-dns.service" ];
      timerConfig = {
        OnBootSec = "0m";
        OnUnitInactiveSec = "3m";

        AccuracySec = "15s";
        RandomizedDelaySec = "15s";
      };
    };
    systemd.services."netcup-dns" = {
      serviceConfig = {
        Type = "oneshot";
        PrivateTmp = true;
        User = "netcup-dns";
        Nice = 19;
        IOSchedulingClass = "idle";

        # Create directory `/run/netcup-dns`.
        # `netcup-dns` uses it for caching.
        # For systemd to create this directory automatically, `PermissionsStartOnly` is required: https://unix.stackexchange.com/questions/354583/how-to-automatically-create-a-runtime-folder-with-a-systemd-service-or-tmpfiles#comment628290_354583
        RuntimeDirectoryMode = "0755";
        RuntimeDirectory = "netcup-dns";
        PermissionsStartOnly = true;
        # Since we use `/run/netcup-dns` for caching between subsequent runs of `netcup-dns`, it should be kept and not deleted.
        # Man page section `RuntimeDirectoryPreserve`:
        #   If set to yes, then the directories are not removed when the service is stopped. Note that since the runtime directory /run/ is a mount point of "tmpfs", then for system services the directories specified in RuntimeDirectory= are removed when the system is rebooted.
        RuntimeDirectoryPreserve = true;

        ExecStart = "${pkgs.python3.withPackages my-python-packages}/bin/netcup-dns --cache-directory /run/netcup-dns";
      };
    };
  };
}