{ config
, lib
, pkgs
, ...
}:
let
  inherit (pkgs) stdenv;
  lsOptions =
    if stdenv.isDarwin
    then "-p"
    else "-v --group-directories-first";
  lsIsoDate =
    if stdenv.isDarwin
    then ""
    else "--time-style=long-iso";
  zshrc = ".config/zsh/.zshrc";
  mkZshPlugin = attrs: {
    name = attrs.name;
    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
    ghq
    git
    git-lfs
    zsh-completions
    up
  ];

  programs.zsh = {
    enable = true;

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

    dotDir = ".config/zsh";

    history = {
      expireDuplicatesFirst = true;
      extended = true;
      path = "$HOME/.local/share/zsh/history";
      save = 200000;
      size = 100000;
      share = false;
    };

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

    plugins = map mkZshPlugin [
      {
        name = "agkozak-zsh-prompt";
        src = pkgs.fetchFromGitHub {
          owner = "agkozak";
          repo = "agkozak-zsh-prompt";
          rev = "87ea6db9375032a6a26496a7f4a6266804f6929a";
          # date = 2021-11-14T17:40:31-08:00;
          sha256 = "08f5q9z7mc2hshnx35nh4gqgdkvjv41704hn69vz0p190fkzx3i0";
        };
      }
      {
        name = "anyframe";
        src = pkgs.fetchFromGitHub {
          owner = "mollifier";
          repo = "anyframe";
          rev = "598675303044df8e9d04722f3adff4f63a238922";
          # date = 2017-07-19T21:59:49+09:00;
          sha256 = "08bjm1dd2mpv8rk8x6yvm6gj490rgimmiq7ln4jr5hik2k3mm82r";
        };
      }
    ];

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

      cg = "cd $(git root)";
      cdg = "cd $(git root)";

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

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

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

      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";
      gf = "git fetch";
      gk = "git push";
      gkf = "git push --force-with-lease";
      gj = "git pull";
      gl = "git lg";
      gm = "git merge";
      ge = "git remote";
      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";
      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";
      nic = "nix-channel";
      nica = "nix-channel --add";
      nicl = "nix-channel --list";
      nicu = "nix-channel --update";
      nicr = "nix-channel --remove";
      nicb = "nix-channel --rollback";
      snic = "sudo nix-channel";
      snica = "sudo nix-channel --add";
      snicl = "sudo nix-channel --list";
      snicu = "sudo nix-channel --update";
      snicr = "sudo nix-channel --remove";
      snicb = "sudo nix-channel --rollback";
      nf = "nix flake";
      nfa = "nix flake archive";
      nfu = "nix flake update";
      nfl = "nix flake lock";
      n = "nix-env";
      ni = "nix-env -iA";
      nq = "nix-env -q";
      ne = "nix-env -e";
      nup = "nix-env -u";
      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";
    };

    envExtra = ''
      if [[ ''${path[(I)$HOME/.local/bin ]} ]]
      then
        path=($HOME/.local/bin $path)
      fi
    '';

    initExtra =
      ''
        typeset -T GHQ_ROOT ghq_root
        export GHQ_ROOT="$HOME/projects"

        function hist-freq-subcommands () {
          fc -l -m "$1*" -10000 | cut -d' ' -f4- | sort | uniq -c | sort -g | tail -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."${zshrc}".onChange = "${pkgs.zsh}/bin/zsh -i -c 'autoload -Uz compinit && compinit && zcompile ${zshrc}'";
}