{
  config,
  lib,
  pkgs,
  ...
}:
let
  inherit (lib) mkOption optionalString types;

  inherit (import ../lib.nix { inherit config lib; }) dotDirRel;

  cfg = config.programs.zsh;

  ohMyZshModule = types.submodule {
    options = {
      enable = lib.mkEnableOption "oh-my-zsh";

      package = lib.mkPackageOption pkgs "oh-my-zsh" { };

      plugins = mkOption {
        default = [ ];
        example = [
          "git"
          "sudo"
        ];
        type = types.listOf types.str;
        description = ''
          List of oh-my-zsh plugins
        '';
      };

      custom = mkOption {
        default = "";
        type = types.str;
        example = "\${config.home.homeDirectory}/my_customizations";
        description = ''
          Path to a custom oh-my-zsh package to override config of
          oh-my-zsh. See <https://github.com/robbyrussell/oh-my-zsh/wiki/Customization>
          for more information.
        '';
      };

      theme = mkOption {
        default = "";
        example = "robbyrussell";
        type = types.str;
        description = ''
          Name of the theme to be used by oh-my-zsh.
        '';
      };

      extraConfig = mkOption {
        default = "";
        example = ''
          zstyle :omz:plugins:ssh-agent identities id_rsa id_rsa2 id_github
        '';
        type = types.lines;
        description = ''
          Extra settings for plugins.
        '';
      };
    };
  };
in
{
  options.programs.zsh.oh-my-zsh = mkOption {
    type = ohMyZshModule;
    default = { };
    description = "Options to configure oh-my-zsh.";
  };

  config = lib.mkIf cfg.oh-my-zsh.enable {
    home = {
      packages = [ cfg.oh-my-zsh.package ];

      file = {
        "${dotDirRel}/.zshenv".text = ''
          ZSH="${cfg.oh-my-zsh.package}/share/oh-my-zsh";
          ZSH_CACHE_DIR="${config.xdg.cacheHome}/oh-my-zsh";
        '';

        # Make sure we create a cache directory since some plugins expect it to exist
        # See: https://github.com/nix-community/home-manager/issues/761
        "${config.xdg.cacheHome}/oh-my-zsh/.keep".text = "";
      };
    };

    programs.zsh.initContent = lib.mkOrder 800 ''
      # oh-my-zsh extra settings for plugins
      ${cfg.oh-my-zsh.extraConfig}
      # oh-my-zsh configuration generated by NixOS
      ${optionalString (
        cfg.oh-my-zsh.plugins != [ ]
      ) "plugins=(${lib.concatStringsSep " " cfg.oh-my-zsh.plugins})"}
      ${optionalString (cfg.oh-my-zsh.custom != "") ''ZSH_CUSTOM="${cfg.oh-my-zsh.custom}"''}
      ${optionalString (cfg.oh-my-zsh.theme != "") ''ZSH_THEME="${cfg.oh-my-zsh.theme}"''}
      source $ZSH/oh-my-zsh.sh
    '';
  };
}
