{ lib }:
let
  inherit (lib) optionalAttrs isAttrs types;
  inherit (lib.nixvim) defaultNullOpts;
in
rec {
  # These are the configuration options that change the behavior of each mapping.
  mapConfigOptions = {
    silent = defaultNullOpts.mkBool false "Whether this mapping should be silent. Equivalent to adding `<silent>` to a map.";

    nowait = defaultNullOpts.mkBool false "Whether to wait for extra input on ambiguous mappings. Equivalent to adding `<nowait>` to a map.";

    script = defaultNullOpts.mkBool false "Equivalent to adding `<script>` to a map.";

    expr = defaultNullOpts.mkBool false "Means that the action is actually an expression. Equivalent to adding `<expr>` to a map.";

    unique = defaultNullOpts.mkBool false "Whether to fail if the map is already defined. Equivalent to adding `<unique>` to a map.";

    noremap = defaultNullOpts.mkBool true "Whether to use the `noremap` variant of the command, ignoring any custom mappings on the defined action. It is highly advised to keep this on, which is the default.";

    remap = defaultNullOpts.mkBool false "Make the mapping recursive. Inverses `noremap`.";

    desc = lib.nixvim.mkNullOrOption lib.types.str "A textual description of this keybind, to be shown in which-key, if you have it.";

    buffer = defaultNullOpts.mkBool false "Make the mapping buffer-local. Equivalent to adding `<buffer>` to a map.";
  };

  modes = {
    normal.short = "n";
    insert.short = "i";
    visual = {
      desc = "visual and select";
      short = "v";
    };
    visualOnly = {
      desc = "visual only";
      short = "x";
    };
    select.short = "s";
    terminal.short = "t";
    normalVisualOp = {
      desc = "normal, visual, select and operator-pending (same as plain 'map')";
      short = "";
    };
    operator.short = "o";
    lang = {
      desc = "normal, visual, select and operator-pending (same as plain 'map')";
      short = "l";
    };
    insertCommand = {
      desc = "insert and command-line";
      short = "!";
    };
    command.short = "c";
  };

  modeEnum =
    lib.types.enum
      # ["" "n" "v" ...]
      (map ({ short, ... }: short) (lib.attrValues modes));

  mapOptionSubmodule = mkMapOptionSubmodule { };

  # NOTE: options that have the deprecated `lua` sub-option must use `removeDeprecatedMapAttrs`
  # to ensure `lua` isn't evaluated when (e.g.) generating lua code.
  # Failure to do so will result in "option used but not defined" errors!
  deprecatedMapOptionSubmodule = mkMapOptionSubmodule { lua = true; };
  removeDeprecatedMapAttrs = v: builtins.removeAttrs v [ "lua" ];

  mkModeOption =
    default:
    lib.mkOption {
      type = with lib.types; either modeEnum (listOf modeEnum);
      description = ''
        One or several modes.
        Use the short-names (`"n"`, `"v"`, ...).
        See `:h map-modes` to learn more.
      '';
      inherit default;
      example = [
        "n"
        "v"
      ];
    };

  mkMapOptionSubmodule =
    {
      # Allow overriding defaults for key, action, mode, etc
      defaults ? { },

      # key and action can be true/false to enable/disable adding the option,
      # or an attrset to enable the option and add/override mkOption args.
      key ? true,
      action ? true,
      lua ? false, # WARNING: for historic use only - do not use in new options!

      # Allow passing additional options or modules to the submodule
      # Useful for plugin-specific features
      extraOptions ? { },
      extraModules ? [ ],
    }:
    types.submodule (
      { config, options, ... }:
      {
        imports = extraModules;

        options =
          (lib.optionalAttrs (isAttrs key || key) {
            key = lib.mkOption (
              {
                type = types.str;
                description = "The key to map.";
                example = "<C-m>";
              }
              // (optionalAttrs (isAttrs key) key)
              // (optionalAttrs (defaults ? key) { default = defaults.key; })
            );
          })
          // (optionalAttrs (isAttrs action || action) {
            action = lib.mkOption (
              {
                type = types.maybeRaw types.str;
                description = "The action to execute.";
                apply = v: if options.lua.isDefined or false && config.lua then lib.nixvim.mkRaw v else v;
              }
              // (optionalAttrs (isAttrs action) action)
              // (optionalAttrs (defaults ? action) { default = defaults.action; })
            );
          })
          // optionalAttrs (isAttrs lua || lua) {
            lua = lib.mkOption (
              {
                type = types.bool;
                description = ''
                  If true, `action` is considered to be lua code.
                  Thus, it will not be wrapped in `""`.

                  This option is deprecated and will be removed in 24.11.
                  You should use a "raw" action instead, e.g. `action.__raw = ""`.
                '';
                visible = false;
              }
              // optionalAttrs (isAttrs lua) lua
            );
          }
          // {
            mode = mkModeOption defaults.mode or "";
            options = mapConfigOptions;
          }
          // extraOptions;
      }
    );

  # Correctly merge two attrs (partially) representing a mapping.
  mergeKeymap =
    defaults: keymap:
    let
      # First, merge the `options` attrs of both options.
      mergedOpts = (defaults.options or { }) // (keymap.options or { });
    in
    # Then, merge the root attrs together and add the previously merged `options` attrs.
    (defaults // keymap) // { options = mergedOpts; };

  mkKeymaps = defaults: map (mergeKeymap defaults);
}