{ config, lib, pkgs, ... }:
with lib;
let
  escape = escapeShellArg;
  cfg = config.rbackup;

  start = name: plan:
    let
      login-name = "root";
      identity = plan.sshKeyPath;
      ssh = "ssh -i ${escape identity}";
    in
    pkgs.writers.writeBash "backup.${name}" ''
      set -efu
      rsync_src=${escape plan.src}
      rsync_dst=${escape plan.dst}
      echo >&2 "update snapshot current; $rsync_dst <- $rsync_src"

      rsync \
          --rsh=${escape ssh} \
          --append -avz \
          ${optionalString plan.delete "--delete"} \
          "$rsync_src/" \
          "$rsync_dst"
    '';

in
{
  options.rbackup = {
    plans = mkOption {
      default = { };
      type = types.attrsOf
        (types.submodule ({ config, ... }: {
          options = {
            sshKeyPath = mkOption {
              type = types.str;
            };
            src = mkOption {
              type = types.str;
            };
            dst = mkOption {
              type = types.str;
            };
            startAt = mkOption {
              default = "hourly";
              type = with types; nullOr str; # TODO systemd.time(7)'s calendar event
            };
            delete = mkOption {
              type = types.bool;
              default = true;
              description = "delete old files (adds the --delete argument to rsync)";
            };
            timerConfig = mkOption {
              type = with types; attrsOf str;
              default = optionalAttrs (config.startAt != null) {
                OnCalendar = config.startAt;
              };
            };
          };
        }));
    };
  };

  config = {

    systemd.services =
      mapAttrs'
        (name: plan: nameValuePair "rbackup.${name}" {
          path = with pkgs; [
            coreutils
            gnused
            openssh
            rsync
            util-linux
          ];
          restartIfChanged = false;
          serviceConfig = rec {
            ExecStart = start name plan;
            SyslogIdentifier = ExecStart.name;
            Type = "oneshot";
          };
        })
        cfg.plans;

    systemd.timers = mapAttrs'
      (name: plan: nameValuePair "rbackup.${name}" {
        wantedBy = [ "timers.target" ];
        timerConfig = plan.timerConfig;
      })
      cfg.plans;

  };

}