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

with lib;
let
  cfg = config.services.sanoid;

  configToText = let
    toString = v:
      if builtins.isBool v then
      	if v then "yes" else "no"
      else builtins.toString v;
    item = k: v: "${k} = ${toString v}";
    items = v: concatStringsSep "\n" (mapAttrsToList item v);
    section = k: v: "[${k}]\n${items v}\n";
  in c: concatStringsSep "\n" (mapAttrsToList section c);

in {
  options.services.sanoid = with types; {
    enable = mkEnableOption "sanoid";
    package = mkOption {
      type = package;
      default = pkgs.sanoid;
    };

    config = mkOption {
      type = attrs;
      default = {};
    };

    configText = mkOption {
      type = lines;
      default = configToText cfg.config;
    };

    configDir = mkOption {
      type = path;
      default = pkgs.runCommandNoCC "sanoid-config" {} ''
      	mkdir $out
        echo '${cfg.configText}' > $out/sanoid.conf
        cp ${cfg.package}/etc/sanoid $out/sanoid.defaults.conf
      '';
    };

    allowPermissions = mkOption {
      type = listOf string;
      default = [];
    };
  };

  config = mkIf cfg.enable {
    users.users.sanoid = {
      isSystemUser = true;
      home = "/var/cache/sanoid";
      createHome = true;
    };

    systemd.services.sanoid = {
      # recommended to prevent problems with daylight saving times (what's the default?)
      environment.TZ = "UTC";

      preStart = ''
        ${lib.concatMapStringsSep "\n"
          (pool: "/run/current-system/sw/bin/zfs allow sanoid snapshot,destroy,mount,send,receive ${lib.escapeShellArg pool}")
	    cfg.allowPermissions}
      '';

      script = ''
        ${cfg.package}/bin/sanoid \
          --cron \
          --verbose \
          --configdir=${cfg.configDir}
      '';

      serviceConfig = {
        User = "sanoid";
        PermissionsStartOnly = true;
      };
    };

    systemd.timers.sanoid = {
      timerConfig.OnCalendar = "minutely";
      wantedBy = [ "timers.target" ];
    };
  };
}