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

let

  cfg = config.xsession.windowManager.herbstluftwm;

  renderValue =
    val: if lib.isBool val then if val then "true" else "false" else lib.escapeShellArg val;

  renderSettings =
    settings:
    lib.concatStringsSep "\n" (
      lib.mapAttrsToList (name: value: "herbstclient set ${name} ${renderValue value}") settings
    );

  renderKeybinds =
    keybinds:
    lib.concatStringsSep "\n" (
      lib.mapAttrsToList (key: cmd: "herbstclient keybind ${key} ${cmd}") keybinds
    );

  renderMousebinds =
    mousebinds:
    lib.concatStringsSep "\n" (
      lib.mapAttrsToList (btn: cmd: "herbstclient mousebind ${btn} ${cmd}") mousebinds
    );

  renderRules = rules: lib.concatStringsSep "\n" (map (rule: "herbstclient rule ${rule}") rules);

  settingType = lib.types.oneOf [
    lib.types.bool
    lib.types.int
    lib.types.str
  ];

  escapedTags = map lib.escapeShellArg cfg.tags;

in
{
  meta.maintainers = [ lib.hm.maintainers.olmokramer ];

  options.xsession.windowManager.herbstluftwm = {
    enable = lib.mkEnableOption "herbstluftwm window manager";

    package = lib.mkPackageOption pkgs "herbstluftwm" { };

    settings = lib.mkOption {
      type = lib.types.attrsOf settingType;
      default = { };
      example = lib.literalExpression ''
        {
          gapless_grid = false;
          window_border_width = 1;
          window_border_active_color = "#FF0000";
        }
      '';
      description = "Herbstluftwm settings.";
    };

    keybinds = lib.mkOption {
      type = lib.types.attrsOf lib.types.str;
      default = { };
      example = {
        Mod4-o = "split right";
        Mod4-u = "split bottom";
      };
      description = "Herbstluftwm keybinds.";
    };

    mousebinds = lib.mkOption {
      type = lib.types.attrsOf lib.types.str;
      default = { };
      example = {
        Mod4-B1 = "move";
        Mod4-B3 = "resize";
      };
      description = "Herbstluftwm mousebinds.";
    };

    rules = lib.mkOption {
      type = lib.types.listOf lib.types.str;
      default = [ ];
      example = [
        "windowtype~'_NET_WM_WINDOW_TYPE_(DIALOG|UTILITY|SPLASH)' focus=on pseudotile=on"
        "windowtype~'_NET_WM_WINDOW_TYPE_(NOTIFICATION|DOCK|DESKTOP)' manage=off"
      ];
      description = "Herbstluftwm rules.";
    };

    tags = lib.mkOption {
      type = lib.types.listOf lib.types.str;
      default = [ ];
      example = [
        "work"
        "browser"
        "music"
        "gaming"
      ];
      description = "Tags to create on startup.";
    };

    extraConfig = lib.mkOption {
      type = lib.types.lines;
      default = "";
      example = ''
        herbstclient set_layout max
        herbstclient detect_monitors
      '';
      description = ''
        Extra configuration lines to add verbatim to
        {file}`$XDG_CONFIG_HOME/herbstluftwm/autostart`.
      '';
    };

    enableAlias = lib.mkOption {
      type = lib.types.bool;
      default = true;
      description = ''
        Set an alias for the {command}`herbstclient` command in the
        {file}`autostart` script that only stores its arguments and executes
        them all at once at the end of the {file}`autostart` script.

        This reduces the amount of flickering you get while all options are
        being applied and improves the performance.

        On the other hand, this makes it more difficult to write bash functions
        that call {command}`herbstclient`. You can work around this by calling
        {command}`command herbstclient` in your functions to still get some of
        the benefits of enabling this alias.
      '';
    };
  };

  config = lib.mkIf cfg.enable {
    assertions = [
      (lib.hm.assertions.assertPlatform "xsession.windowManager.herbstluftwm" pkgs lib.platforms.linux)
    ];

    home.packages = [ cfg.package ];

    xsession.windowManager.command = "${cfg.package}/bin/herbstluftwm --locked";

    xdg.configFile."herbstluftwm/autostart".source = pkgs.writeShellScript "herbstluftwm-autostart" ''
      ${lib.optionalString cfg.enableAlias ''
        shopt -s expand_aliases

        # shellcheck disable=SC2142
        alias herbstclient='set -- "$@" ";"'
        set --
      ''}

      herbstclient emit_hook reload

      # Reset everything.
      herbstclient attr theme.tiling.reset 1
      herbstclient attr theme.floating.reset 1
      herbstclient keyunbind --all
      herbstclient mouseunbind --all
      herbstclient unrule --all

      ${renderSettings cfg.settings}

      ${lib.optionalString (cfg.tags != [ ]) ''
        for tag in ${lib.concatStringsSep " " escapedTags}; do
          herbstclient add "$tag"
        done

        if ${cfg.package}/bin/herbstclient object_tree tags.by-name.default &>/dev/null; then
          herbstclient use ${lib.head escapedTags}
          herbstclient merge_tag default ${lib.head escapedTags}
        fi
      ''}

      ${renderKeybinds cfg.keybinds}

      ${renderMousebinds cfg.mousebinds}

      ${renderRules cfg.rules}

      ${cfg.extraConfig}

      herbstclient unlock

      ${lib.optionalString cfg.enableAlias ''
        ${cfg.package}/bin/herbstclient chain ";" "$@"
      ''}
    '';
  };
}
