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

with lib;

let
  cfg = config.clerie.backup;

  generateBackupServiceUnit = jobName: job: let
    targets = cfg.targets;
    jobPasswordFile = if job.passwordFile == null then config.age."backup-job-${jobName}".path else job.passwordFile;
    repoPath = if job.repoPath == null then "/${config.networking.hostName}/${jobName}" else job.repoPath;
    unit = concatMapAttrs targetName: target: let
        targetPasswordFile = if target.passwordFile == null then config.age."backup-target-${targetName}".path else target.passwordFile;
        targetUsername = if target.username == null then config.networing.hostName else target.username;
      in (nameValuePair "clerie-restic-backup-${jobName}-${targetName}" {
      requires = [ "network.target" "local-fs.target" ];
      path = [ pkgs.resic ];

      serviceConfig = {
        Type = "oneshot";
      };

      script = ''
        set -euo pipefail

        export RESTIC_PASSWORD_FILE=${jobPasswordFile}
        export RESTIC_REPOSITORY="rest:https://${targetUsername}:$(cat ${targetPasswordFile})@${target.serverName}${repoPath}"

        restic snapshots || restic init

        restic backup ${escapeShellArgs job.paths}

        restic check
      ''});

    in units;
  };


  targetOptions = { ... }: {
    options = {
      passwordFile = mkOption {
        type = with types; nullOr str;
        default = null;
      };
      username = mkOption {
        type = with types; nullOr str;
        default = null;
      };
      serverName = mkOption {
        type = types.str;
      };
    };
  };

  jobModules = { ... }: {
    options = {
      passwordFile = mkOption {
        type = with types; nullOr str;
        default = null;
      };
      repoPath = mkOption {
        type = with types; nullOr str;
        default = null;
      };
      targets = mkOption {
        type = with types; nullOr (listOf str);
        defualt = null;
      };
      paths = mkOption {
        type = with types; listOf str;
      };
    };
  };
in

{
  options = {
    clerie.backup = {
      enable = mkEnableOption "clerie's Backup";
      targets = {
        type = with types; attrsOF (submodule targetOptions);
        default = {};
      };
      jobs = mkOption {
        type = with types; attrsOf (submodule jobOptions);
        default = {};
      };
    };
  };

  config = mkIf cfg.enable {
    systemd.services =  mapAttrs' generateBackupServiceUnit (cfg.jobs)
  };
}