{ config, lib, pkgs, ... }:
let
  passwordstoreDir = "\${PASSWORD_STORE_DIR:-$HOME/.password-store}";
in
{
  options.clan.password-store.targetDirectory = lib.mkOption {
    type = lib.types.path;
    default = "/etc/secrets";
    description = ''
      The directory where the password store is uploaded to.
    '';
  };
  config = lib.mkIf (config.clanCore.secretStore == "password-store") {
    clanCore.secretsDirectory = config.clan.password-store.targetDirectory;
    clanCore.secretsUploadDirectory = config.clan.password-store.targetDirectory;
    system.clan.generateSecrets = lib.mkIf (config.clanCore.secrets != { }) (
      pkgs.writeScript "generate-secrets" ''
        #!/bin/sh
        set -efu

        test -d "$CLAN_DIR"
        PATH=${lib.makeBinPath [
          pkgs.pass
        ]}:$PATH

        # TODO maybe initialize password store if it doesn't exist yet

        ${lib.foldlAttrs (acc: n: v: ''
          ${acc}
          # ${n}
          # if any of the secrets are missing, we regenerate all connected facts/secrets
          (if ! (${lib.concatMapStringsSep " && " (x: "test -e ${passwordstoreDir}/machines/${config.clanCore.machineName}/${x.name}.gpg >/dev/null") (lib.attrValues v.secrets)}); then

            tmpdir=$(mktemp -d)
            trap "rm -rf $tmpdir" EXIT
            cd $tmpdir

            facts=$(mktemp -d)
            trap "rm -rf $facts" EXIT
            secrets=$(mktemp -d)
            trap "rm -rf $secrets" EXIT
            ( ${v.generator} )

            ${lib.concatMapStrings (fact: ''
              mkdir -p "$CLAN_DIR"/"$(dirname ${fact.path})"
              cp "$facts"/${fact.name} "$CLAN_DIR"/${fact.path}
            '') (lib.attrValues v.facts)}

            ${lib.concatMapStrings (secret: ''
              cat "$secrets"/${secret.name} | pass insert -m machines/${config.clanCore.machineName}/${secret.name}
            '') (lib.attrValues v.secrets)}
          fi)
        '') "" config.clanCore.secrets}
      ''
    );
    system.clan.uploadSecrets = pkgs.writeScript "upload-secrets" ''
      #!/bin/sh
      set -efu

      umask 0077

      PATH=${lib.makeBinPath [
        pkgs.pass
        pkgs.git
        pkgs.findutils
        pkgs.rsync
      ]}:$PATH:${lib.getBin pkgs.openssh}

      if test -e ${passwordstoreDir}/.git; then
        local_pass_info=$(
          git -C ${passwordstoreDir} log -1 --format=%H machines/${config.clanCore.machineName}
          # we append a hash for every symlink, otherwise we would miss updates on
          # files where the symlink points to
          find ${passwordstoreDir}/machines/${config.clanCore.machineName} -type l \
              -exec realpath {} + |
            sort |
            xargs -r -n 1 git -C ${passwordstoreDir} log -1 --format=%H
        )
        remote_pass_info=$(ssh ${config.clan.networking.deploymentAddress} -- ${lib.escapeShellArg ''
          cat ${config.clan.password-store.targetDirectory}/.pass_info || :
        ''} || :)

        if test "$local_pass_info" = "$remote_pass_info"; then
          echo secrets already match
          exit 23
        fi
      fi

      find ${passwordstoreDir}/machines/${config.clanCore.machineName} -type f -follow ! -name .gpg-id |
      while read -r gpg_path; do

        rel_name=''${gpg_path#${passwordstoreDir}}
        rel_name=''${rel_name%.gpg}

        pass_date=$(
          if test -e ${passwordstoreDir}/.git; then
            git -C ${passwordstoreDir} log -1 --format=%aI "$gpg_path"
          fi
        )
        pass_name=$rel_name
        tmp_path="$SECRETS_DIR"/$(basename $rel_name)

        mkdir -p "$(dirname "$tmp_path")"
        pass show "$pass_name" > "$tmp_path"
        if [ -n "$pass_date" ]; then
          touch -d "$pass_date" "$tmp_path"
        fi
      done

      if test -n "''${local_pass_info-}"; then
        echo "$local_pass_info" > "$SECRETS_DIR"/.pass_info
      fi
    '';
  };
}

