{ config
, lib
, pkgs
, ...
}:
let
  inherit (pkgs) stdenv;
  lsOptions =
    if stdenv.isDarwin
    then "-p"
    else "-v --group-directories-first --hyperlink=auto";
  lsIsoDate =
    if stdenv.isDarwin
    then ""
    else "--time-style=long-iso";
  zshrc = ".config/zsh/.zshrc";
  mkZshPlugin = attrs@{ name, file ? "${name}.plugin.zsh", ... }: {
    inherit name file;
    src = stdenv.mkDerivation {
      inherit (attrs) src;
      name = "zsh-plugin-${attrs.name}";
      buildInputs = [ pkgs.zsh ];
      buildPhase = ''
        zsh -c 'for f in **/*.zsh; zcompile "$f"'
      '';
      installPhase = ''
        cp -a $PWD $out/
      '';
    };
  };
in
{
  home.packages = with pkgs; [
    fzf
    gh
    ghq
    delta
    git
    gitui
    gitstatus
    git-lfs
    zsh-completions
    up
  ];

  programs.zsh = {
    enable = true;

    enableAutosuggestions = true;
    enableCompletion = true;
    defaultKeymap = "emacs";

    dotDir = ".config/zsh";

    history = {
      expireDuplicatesFirst = true;
      extended = true;
      path = "${config.home.homeDirectory}/.local/share/zsh/history";
      save = 200000;
      size = 100000;
      share = false;
      ignorePatterns = [
        "rm *"
        "trash *"
        "pkill *"
        "* aria2c *"
      ];
    };

    localVariables = {
      ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE = "fg=8";
    };

    plugins = map mkZshPlugin [
      {
        name = "zsh-bd";
        file = "bd.plugin.zsh";
        src = pkgs.zsh-bd.src;
      }
      {
        name = "zsh-autopair";
        src = pkgs.zsh-autopair.src;
      }
      {
        name = "anyframe";
        src = pkgs.fetchFromGitHub {
          owner = "mollifier";
          repo = "anyframe";
          rev = "598675303044df8e9d04722f3adff4f63a238922";
          # date = 2017-07-19T21:59:49+09:00;
          sha256 = "08bjm1dd2mpv8rk8x6yvm6gj490rgimmiq7ln4jr5hik2k3mm82r";
        };
      }
      {
        name = "zsh-powerlevel10k";
        src = pkgs.zsh-powerlevel10k.src;
        file = "dummy";
      }
    ];

    shellAliases = {
      l = "ls ${lsOptions} -Bp";
      l1 = "ls -1";
      ls = "ls ${lsOptions} -hF";
      la = "ls ${lsOptions} -hA";
      ll = "ls ${lsOptions} ${lsIsoDate} -hl";
      lal = "ll -A";
      lla = "lal";
      llr = "ll -t";

      c = "tere";
      "c," = "cd $(ghq list -p nixfiles)";
      cg = "cd $(git root)";
      cdg = "cd $(git root)";

      http = "xh";
      https = "xh --default-scheme https";
      xhs = "xh --default-scheme https";

      history = "fc -l $(( $LINES - 2 ))";
      hist-freq-lines = "fc -l -10000 | cut -d' ' -f4- | sort | uniq -c | sort -gr | head -n100 | less";
      hist-freq-commands = "fc -l -10000 | cut -d' ' -f4 | sort | uniq -c | sort -gr | head -n10 | less";
      wprop = "xprop | egrep '^WM_(CLASS|NAME|WINDOW_ROLE|TYPE)'";

      # Enable the following commands to support aliases.
      sudo = "sudo ";
      watch = "watch ";

      e = "$EDITOR";
      se = "sudo -e";

      ip = "ip --color=auto";
      ip4 = "ip -4";
      ip6 = "ip -6";

      d = "docker";
      db = "docker build";
      dr = "docker run";
      di = "docker image";
      dj = "docker pull";
      dk = "docker push";

      dcb = "dc build";
      dcd = "dc down";
      dcj = "dc pull";
      dck = "dc push";
      dcl = "dc logs";
      dclf = "dc logs -f";
      dcu = "dc up";
      dcud = "dc up -d";
      dcr = "dc restart";

      ga = "git add";
      gs = "git st";
      gd = "git diff";
      gdc = "git diff --cached";
      gf = "git fetch";
      gk = "git push";
      gkf = "git push --force-with-lease";
      gj = "git pull";
      gl = "git lg";
      gm = "git merge";
      ge = "git remote";
      ges = "git remote -v show";
      gr = "git rebase";
      gz = "git stash";
      gzl = "git stash list";
      gzp = "git stash pop";
      gdt = "git difftool";
      grl = "git reflog";
      gri = "git rebase --interactive";
      gfa = "git fetch --all";
      grs = "git reset";
      grsh = "git reset --hard";
      gsh = "git show";
      gsm = "git submodule";
      gci = "git commit";
      gx = "git restore";
      gb = "git switch";
      gbr = "git br";
      gbrc = "git checkout -b";
      gbrd = "git branch --delete";
      gbrm = "git branch --move";
      gmup = "git mup";
      grup = "git rup";

      ho = "home-manager";
      hob = "home-manager build";
      hos = "home-manager switch";
      hor = "$(nix-shell -p home-manager --run 'home-manager generations' | head -n 2 | tail -n 1 | f 7)/activate";
      hon = "home-manager news";
      hoh = "home-manager help";
      hop = "home-manager packages";
      hol = "home-manager generations";
      hox = "home-manager expire-generations '-30 days'";

      nish = "nix-shell";
      nf = "nix flake";
      nfa = "nix flake archive";
      nfp = "nix flake prefetch";
      nfu = "nix flake update";
      nfl = "nix flake lock";
      nlg = "nix-env --list-generations";
      snlg = "sudo nix-env --list-generations --profile /nix/var/nix/profiles/system";
      ngc = "nix-collect-garbage --delete-older-than 30d";
      sngc = "sudo nix-collect-garbage --delete-older-than 30d";
    };

    # Put this in /etc/paths.d/ on Darwin instead
    envExtra = lib.optionalString (!stdenv.isDarwin) ''
      if [[ ''${path[(I)$HOME/.local/bin ]} ]]
      then
        path=($HOME/.local/bin $path)
      fi
    '';

    initExtraFirst = ''
      if [[ $TERM != "dumb" ]]
      then
        if [[ -r "${config.xdg.cacheHome}/p10k-instant-prompt-''${(%):-%n}.zsh" ]]; then
          source "${config.xdg.cacheHome}/p10k-instant-prompt-''${(%):-%n}.zsh"
        fi
        typeset -g POWERLEVEL9K_DISABLE_CONFIGURATION_WIZARD=true
        source $ZDOTDIR/plugins/zsh-powerlevel10k/powerlevel10k.zsh-theme
      fi
    '';
    initExtra =
      ''
        typeset -T GHQ_ROOT ghq_root
        export GHQ_ROOT="${config.home.homeDirectory}/projects"

        function hist-freq-subcommands () {
          fc -l -m "$1*" -10000 | cut -d' ' -f4- | sort | uniq -c | sort -gr | head -n100 | less
        }

        source ${pkgs.fzf}/share/fzf/key-bindings.zsh
        source ${pkgs.fzf}/share/fzf/completion.zsh

      ''
      + builtins.readFile ../zsh/zshrc
      + (
        if stdenv.isDarwin
        then builtins.readFile ../zsh/zshrc.darwin
        else ""
      );
  };

  home.file."${config.xdg.configHome}/zsh/.p10k.zsh".source = ../zsh/p10k.zsh;
}