{
  pkgs,
  lib,
  config,
  ...
}:
with lib;
let
  cfg = config.security.systemd-creds;
in
{
  options.security.systemd-creds = {
    target = mkOption {
      type = types.str;
      description = ''
        Destination address of the target host able to encrypt the credentials.
        Used by the default {option}`security.systemd-creds.shell`.
      '';
      default = "root@${config.networking.hostName}.${config.networking.domain}";
      defaultText = mdLiteral "root@\${config.networking.hostName}.\${config.networking.domain}";
      example = mdLiteral "''${config.networking.hostName}.wg";
    };
    decrypt = mkOption {
      type = with types; listOf str;
      description = mdDoc ''
        Command to get the cleartext of a credential.
        `credBase` is derived from the path of the credential in `LoadCredentialEncrypted=`,
        by removing the `builtins.storeDir` prefix and then one directory level.
      '';
      apply = concatStringsSep " ";
      default = [
        "gpg"
        "--batch"
        "--decrypt"
        "\${credBase%.cred}.gpg"
      ];
      example = [
        "pass"
        "\${credBase%.cred}"
      ];
    };
    shell = mkOption {
      type = with types; listOf str;
      description = mdDoc ''
        Command to get a shell on the target host.
      '';
      apply = concatStringsSep " ";
      default = [
        "ssh"
        "-o"
        "StrictHostKeyChecking=yes"
        "-o"
        "ControlMaster=auto"
        "-o"
        "ControlPersist=16s"
        "\"\${SYSTEMD_CREDS_TARGET:-${cfg.target}}\""
      ];
      defaultText = mdLiteral ''
        ssh -o StrictHostKeyChecking=yes \
            -o ControlMaster=auto \
            -o ControlPersist=16s \
            \"''${SYSTEMD_CREDS_TARGET:-root@''${config.security.systemd-creds.target}}\"
      '';
      example = [ "sudo" ];
    };
    encrypt = mkOption {
      type = with types; listOf str;
      description = mdDoc ''
        Command to run `systemd-creds encrypt` on the target host.

        ::: {.warning}
        Beware that the files `/etc/machine-id`
        and `/var/lib/systemd/credential.secret` on the target host,
        are both used to encrypt and decrypt when using the `host` key mechanism.
        Meaning that reinstalling the system on a new drive
        without restoring those two files
        will require to reencrypt the credentials.
        :::
      '';
      apply = concatStringsSep " ";
      default = [
        "systemd-creds"
        "encrypt"
        "--name"
        "\"$credID\""
        "--with-key=auto"
      ];
      example = [
        "sudo"
        "systemd-creds"
        "encrypt"
        "--with-key=host"
      ];
    };
    install = mkOption {
      type = with types; listOf str;
      apply = concatStringsSep " ";
      description = mdDoc ''
        Command to install the encrypted credential on the orchestrating host.
      '';
      default = [
        "install"
        "-D"
        "-m"
        "640"
        "/dev/stdin"
        "\"$credBase\""
      ];
    };
    reencrypt = mkOption {
      type = types.lines;
      apply = pkgs.writeShellScriptBin "systemd-creds-encrypt-${
        replaceStrings [ "@" ] [ "-" ] cfg.target
      }";
      description = mdDoc ''
        Encrypt credentials referenced in the `LoadCredentialEncrypted=`
        of enabled systemd services, by running `systemd-creds` on the {option}`security.systemd-creds.target` host.
        Only *non-existing* credential files are considered,
        unless the `SYSTEMD_CREDS_FORCE_REENCRYPT` envvar is set to a non-empty value.
        Credential directories are not supported.

        Example of use:
        ```console
        $ sudo wg genkey | gpg --encrypt --sign --recipient @$USER --output wireguard/wg-intra/privateKey.gpg
        $ git add wireguard/wg-intra/privateKey.gpg
        ```

        ```nix
        { config, pkgs, lib, inputs, ... }:
        {
        systemd.services."wireguard-wg-intra".serviceConfig.LoadCredentialEncrypted =
          [ "privateKey:''${inputs.self}/wireguard/wg-intra/privateKey.cred" ];
        }
        ```

        ```console
        $ nix run .#nixosConfigurations.''${hostName}.config.security.systemd-creds.reencrypt
        $ git add wireguard/wg-intra/privateKey.cred
        ```

        ::: {.warning}
        To be able to access the relative path of the `.cred` file,
        `inputs.self` has to be used in `LoadCredentialEncrypted=`.
        Note that `inputs` is a `config._module.args` or `specialArgs`
        usually set in your `flake.nix`.
        In other words, using `''${wireguard/wg-intra/privatekey}` here,
        would not work, because it drops the `wireguard/wg-intra/` part.
        :::
      '';
    };
  };
  config = {
    security.systemd-creds.reencrypt =
      ''
        shopt -s extglob globstar nullglob
        set -o pipefail
        set -eux
      ''
      +
        concatMapStringsSep "\n"
          (
            service:
            concatMapStringsSep "\n" (
              credential:
              let
                cred = splitString ":" credential;
                credID = elemAt cred 0;
                credPath = elemAt cred 1;
              in
              ''
                credID=${escapeShellArg credID}
                credPath=${escapeShellArg credPath}
                credBase=''${credPath#${builtins.storeDir}/*/}
                if test "''${SYSTEMD_CREDS_FORCE_REENCRYPT:+set}" \
                        -o ! -s "$credBase" \
                        -o -e "''${credBase%.cred}.gpg" -a "$credBase" -ot "''${credBase%.cred}.gpg"; then
                  { ${cfg.decrypt}; } |
                  { ${cfg.shell} -- ${cfg.encrypt} - -; } |
                  { ${cfg.install}; }
                fi
              ''
            ) (toList service.serviceConfig.LoadCredentialEncrypted)
          )
          (
            attrValues (
              filterAttrs (
                _serviceName: service: service.enable && hasAttr "LoadCredentialEncrypted" service.serviceConfig
              ) config.systemd.services
            )
          );
  };
}