{ config, pkgs, ... }:
{
  # https://nixos.wiki/wiki/Docker#Installation

  # TODO: rootless Docker. https://nixos.wiki/wiki/Docker#Rootless_docker
  # TODO: run as systemd services. https://nixos.wiki/wiki/Docker#docker_containers_as_systemd_services

  virtualisation = {
    docker = {
      enable = true;

      # As we use btrfs, we enable the according storageDriver option.
      storageDriver = "btrfs";

      # IPv6 support.
      # https://search.nixos.org/options?channel=23.05&show=virtualisation.docker.daemon.settings
      # https://docs.docker.com/config/daemon/ipv6/#use-ipv6-for-the-default-bridge-network
      # TODO: See notes in Jinja-Compose/proxy.yml.jinja2 why this is not yet ready to use.
#      daemon.settings = {
#        # Enable IPv6 networking on the default network.
#        ipv6 = true;
#        # Assign a subnet to the default bridge network, enabling dynamic IPv6 address allocation.
#        fixed-cidr-v6 = "2001:db8:1::/64";
#        # Enable additional IPv6 packet filter rules, providing network isolation and port mapping.
#        # This parameter requires experimental to be set to `true`.
#        ip6tables = true;
#        experimental = true;
#      };

      # Run `docker system prune -f ${autoPrune.flags}` every week.
      # This creates `docker-prune.service` and `docker-prune.timer`.
      autoPrune.enable = true;
      autoPrune.dates = "weekly";
      # https://docs.docker.com/engine/reference/commandline/system_prune/#options
      autoPrune.flags = [
        "--all"
        # https://docs.docker.com/engine/reference/commandline/system_prune/#filter
        # https://pkg.go.dev/maze.io/x/duration#ParseDuration
        # `7d` could not be parsed, thus we use `168h`
        "--filter until=168h"
        # `--volumes` can't be used together with `--filter`.
        # Thus we added our own service below.
        #--volumes
      ];
    };
  };

  # Prune docker volumes.
  # This is a slightly modified copy of https://github.com/NixOS/nixpkgs/blob/5a237aecb57296f67276ac9ab296a41c23981f56/nixos/modules/virtualisation/docker.nix#L211C5-L226
  systemd.services."docker-prune-volumes" = {
    description = "Prune docker volumes";
    restartIfChanged = false;
    unitConfig.X-StopOnRemoval = false;
    serviceConfig.Type = "oneshot";
    script = ''
      ${pkgs.docker}/bin/docker system prune -f --all --volumes
    '';

    # Run weekly after `docker-prune.service` has finished.
    # Reason: Only one `docker system prune` command can be run at a time.

    startAt = "weekly";
    # Start the specified units when this unit is started,
    # and stop this unit when the specified units are stopped or fail.
    requires = [ "docker.service" ];
    # If the specified units are started at the same time as this unit,
    # delay this unit until they have started.
    after = [ "docker.service" "docker-prune.service" ];
  };

  # Monitor unhealthy Docker containers.
  systemd.timers."docker-health" = {
    wantedBy = [ "timers.target" ];
    partOf = [ "docker-health.service" ];
    timerConfig = {
      OnBootSec = "0m";
      OnUnitInactiveSec = "3m";

      AccuracySec = "15s";
      RandomizedDelaySec = "15s";
    };
  };
  systemd.services."docker-health" = {
    serviceConfig = {
      Type = "oneshot";
      PrivateTmp = true;
      # `docker` requires root access.
      User = "root";
      Nice = 19;
      IOSchedulingClass = "idle";
    };
    path = with pkgs; [
      docker
    ];
    # If there are no unhealthy Docker containers, the output of `docker ps -f health=unhealthy` is just one line:
    #   CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
    # We filter this line with `grep -v`.
    # As a result, grep returns exit code 1 if there are no unhealthy containers (as not a single line is printed).
    # Thus, we prefix the whole command with `!`.
    # Lastly, we redirect stdout to stderr with `1>&2` so that unhealthy containers are written to stderr.
    script = ''
      set -eu -o pipefail
      ! sudo docker ps -f health=unhealthy | grep -v 'CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES' 1>&2
    '';
  };
}
