{ 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 = false;
    defaultKeymap = "emacs";

    dotDir = ".config/zsh";

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

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

    plugins = (map mkZshPlugin [
      {
        name = "cd-gitroot";
        src = pkgs.fetchFromGitHub {
          owner = "mollifier";
          repo = "cd-gitroot";
          rev = "66f6ba7549b9973eb57bfbc188e29d2f73bf31bb";
          # date = 2020-06-04T19:40:14+09:00;
          sha256 = "00aj9z3fa6ghjpz7s9cdqpfy4vh1v19z284p4f7xj0z40vrlbdx4";
        };
      }
      {
        name = "agkozak-zsh-prompt";
        src = pkgs.fetchFromGitHub {
          owner = "agkozak";
          repo = "agkozak-zsh-prompt";
          rev = "880ab698199c45120c295da5eb13381a658f40b4";
          # date = 2020-07-09T09:19:39-07:00;
          sha256 = "0avpkh0pp56hi7zqk8fx4580v2w5gaxkdk856ywcd8khwnm6fdpj";
        };
      }
      {
        name = "anyframe";
        src = pkgs.fetchFromGitHub {
          owner = "mollifier";
          repo = "anyframe";
          rev = "598675303044df8e9d04722f3adff4f63a238922";
          # date = 2017-07-19T21:59:49+09:00;
          sha256 = "08bjm1dd2mpv8rk8x6yvm6gj490rgimmiq7ln4jr5hik2k3mm82r";
        };
      }
      {
        name = "fzf-zsh-completions";
        src = pkgs.fetchFromGitHub {
          owner = "chitoku-k";
          repo = "fzf-zsh-completions";
          rev = "19f92960538f0080d040c8ed774d465b9b46e1d1";
          # date = 2021-04-02T17:42:59+09:00;
          sha256 = "0qmm0xm1aiy3fnn2vib26z10cfy707yqg0vg5236r7978glswdlg";
        };
      }
    ]);

    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-gitroot";
      cdg = "cd-gitroot";

      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";
      hos = "home-manager switch";
      hon = "home-manager news";
      hoh = "home-manager help";
      hop = "home-manager packages";
      hol = "home-manager generations";

      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";
      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

      if [[ ''${path[(I)$HOME/go/bin ]} ]]
      then
        path+=($HOME/go/bin)
      fi
    '';

    initExtra = ''
      autoload -Uz compinit
      compinit -C
      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}'";
}