{ pkgs, lib, ... }:

let
  inherit (import ./const.nix) fontSize homedir gpgid;
  locale = "en_US.UTF-8";
in {
  nixpkgs.overlays = [ (import ../overlay.nix) ];
  home = {
    stateVersion = "18.09";
    sessionVariables = {
      GPGID = gpgid;
      EDITOR = "vim";
      LANG = locale;
      # LC_ALL = locale; # bash prints an error when I try to set this
      LANGUAGE = locale;
      PATH = "${homedir}/bin:${homedir}/.local/bin:$PATH";
      PAGER = "less"; # "bat --theme=ansi";
      XTERM_LOCALE = locale;
      PYTHONSTARTUP = "${homedir}/.pythonrc";

      FD_OPTIONS = "--follow --exclude .git";
      BAT_PAGER = "less -R";
      # FZF_DEFAULT_OPTS = "--bind='?:toggle-preview'";
      # FZF_DEFAULT_COMMAND = "git ls-files --cached --others --exclude-standard | fd --type f --type l $FD_OPTIONS";
      # FZF_CTRL_T_COMMAND = "fd $FD_OPTIONS";
      # FZF_ALT_C_COMMAND = "fd --type d $FD_OPTIONS";
      FORGIT_FZF_DEFAULT_OPTS = ''
        --exact
        --border
        --cycle
        --reverse
      '';
    };

    # From the command line:
    #     setxkbmap -option caps:ctrl_modifier
    keyboard.options = [ "caps:ctrl_modifier" ];

    file = {
      yubikeys = {
        source = ./authorized_yubikeys;
        target = ".yubico/authorized_yubikeys";
      };
      editorconfig = {
        source = ./editorconfig;
        target = ".editorconfig";
      };
      pythonrc = {
        source = ./pythonrc;
        target = ".pythonrc";
      };
      pdbrc = {
        source = ./pythonrc;
        target = ".pdbrc";
      };
      # Idk why this doesn't work, less says it can't use my lesskey file
      #less = {
      #  source = ./lesskey;
      #  target = ".less";
      #};
      userstyles = {
        source = ./userstyles.css;
        target = ".userstyles.css";
      };
    };
  };

  programs = {
    home-manager = {
      enable = true;
    };

    readline = {
      enable = true;
      variables = {
        keyseq-timeout = 1200;
        colored-stats = true;
        colored-completion-prefix = true;
        expand-tilde = true;
      };
      bindings = {
        # wrap a command in '$(...| fzf)'
        "\\C-xf" = ''"\C-e | fzf)\C-a(\C-a$\C-b\C-a"'';
        "\\e\\C-f" = "dump-functions"; # help
        "\\e\\C-o" = "dabbrev-expand"; # expand
        "\\e\\C-v" = "dump-variables"; # help
        "\\em" = "beginning-of-line";
        # emacs-like history navigation
        "\\en" = "next-history";
        "\\ep" = "previous-history";
      };
      extraConfig = ''
        $if Guile
          "\C-o": "()\C-b"
        $endif
      '';
    };

    fzf = {
      enable = true;
      enableBashIntegration = true;
      defaultCommand = "rg --files";
      changeDirWidgetCommand = "fd --type d"; # M-c
      changeDirWidgetOptions = ["--preview 'tree -C {} | head -100'"];
      fileWidgetCommand = "fd --type f";
      fileWidgetOptions = ["--preview 'head -n100 {}'"];
      historyWidgetOptions = ["--sort" "--exact"];
      tmux.enableShellIntegration = true;
      tmux.shellIntegrationOptions = [ "-p 70%" ];
    };

    git = {
      enable = true;
      userName = "Ben Sima";
      userEmail = "ben@bsima.me";
      ignores = [ "*~" "*.swp" ];
      package = pkgs.gitAndTools.gitFull;
      signing = {
        key = gpgid;
        # for some reason this fails...
        #gpgPath =
        #  let
        #    script = pkgs.writeScriptBin "my-ots-git-gpg-wrapper" ''
        #      #!/usr/bin/env bash
        #      set -euxo pipefail
        #      ${pkgs.opentimestamps-client}/bin/ots-git-gpg-wrapper --gpg-program ${pkgs.gnupg}/bin/gpg $@
        #    '';
        #  in
        #    "${script}/bin/my-ots-git-gpg-wrapper";
      };
      aliases = {
        authors = "shortlog -s -n";
        slog = "log --stat";
        glog = ''log --decorate --all --graph --pretty=format:"%Cred%h%Creset %an: %s - %Creset %C(yellow)%d%Creset %Cgreen(%cr)%Creset" --abbrev-commit --date=relative'';
      };
      extraConfig = {
        commit.template = "${./git-commit-template}";
        commit.verbose = "true";
        fetch.showForcedUpdate = "false";
        init.defaultBranch = "main";
        log.date = "local";
        merge.tool = "fugitive";
        mergetool.fugitive.cmd = ''vim -f -c "Gvdiffsplit!" "$MERGED"'';
        pull.rebase = "true";
        push.default = "current";
        remote.pushDefault = "origin";
        sendemail = {
          #smtpuser = "ben@bsima.me";
          #smtpserverport = 587;
          smtpserver = "${homedir}/bin/sendmail";
          chainreplyto = false;
          composeencoding = "UTF-8";
          annotate = "yes";
          cccmd = "git-contacts";
        };

      };
    };

    tmux = {
      enable = true;
      aggressiveResize = false;
      baseIndex = 0;
      clock24 = true;
      customPaneNavigationAndResize = false;
      disableConfirmationPrompt = false;
      escapeTime = 0;
      historyLimit = 10000;
      keyMode = "emacs";
      newSession = false;
      resizeAmount = 5;
      reverseSplit = false;
      secureSocket = false;
      sensibleOnTop = true;
      #shell = "${pkgs.bash}/bin/bash";
      shortcut = "a";
      terminal = "xterm-256color";
      tmuxinator.enable = false;
      tmuxp.enable = false;

      extraConfig = ''
        # Automatically set window title
        set-window-option -g automatic-rename on
        set-option -g set-titles on
        set -g xterm-keys on
        setw -g mouse on
        ## Panes
        # Split panes
        bind-key | split-window -h -c "#{pane_current_path}"
        bind-key - split-window -v -c "#{pane_current_path}"
        # Send/join panes
        bind-key j command-prompt -p "join pane from:"  "join-pane -s '%%'"
        bind-key s command-prompt -p "send pane to:"  "join-pane -t '%%'"
        # Use Alt-vim keys without prefix key to switch panes
        bind -n M-h select-pane -L
        bind -n M-j select-pane -D
        bind -n M-k select-pane -U
        bind -n M-l select-pane -R
        # Use Alt-vim capitalized keys without prefix key to resize panes
        bind -n M-H resize-pane -L
        bind -n M-J resize-pane -D
        bind -n M-K resize-pane -U
        bind -n M-L resize-pane -R
        # Shift arrow to switch windows
        bind -n S-Left  previous-window
        bind -n S-Right next-window
        # Set current window pane to 80 columns
        bind-key E resize-pane -x 80
        # cycle pane layout
        bind-key N next-layout
        bind-key P previous-layout
        # Toggle synchronizing panes
        bind-key y setw synchronize-panes
        ## Text manipulation
        # vim-like copy/paste
        setw -g mode-keys vi
        bind [ copy-mode
        bind ] paste-buffer
        # copy/paste with xclip
        bind-key -Tcopy-mode-vi y send-keys -X copy-pipe-and-cancel 'xclip -sel clip -i'
        # select buffer to paste from
        bind Space choose-buffer
        # status line text
        set -g status-left-length 30
        set -g status-left '#S | #(whoami)@#(hostname) | '
        set -g status-right '~%Y.%m.%d..%H.%M'
        set -g renumber-windows on
        # white-ish background with dark-grey text
        set -g status-style bg=colour0,fg=colour13
        # highlight current window
        set -g window-status-current-style fg=colour0,bg=colour13
        set -g window-status-format '#I) #W '
        set -g window-status-current-format '#I) #W '
        # special thing for groq's SFT thing
        set -g update-environment "SFT_AUTH_SOCK SSH_AUTH_SOCK SSH_CONNECTION"
      '';

      plugins = with pkgs.tmuxPlugins; [
        extrakto
        tmux-fzf
      ];
    };

    urxvt = let font = size: "xft:Fira Mono:size=${toString size}:ant"; in {
      enable = true;
      fonts = [
        # for some reason, urxvt font size is much larger than every other
        # program's, so i gotta cut it in half
        (font (fontSize / 2))
        "xft:Noto Emoji"
      ];
      keybindings = {
        # why don't any of these work?
        "Shift-Control-C" = "eval:selection_to_clipboard";
        "Shift-Control-V" = "eval:paste_clipboard";
        "Shift-Control-+" = "command:\033]710;${font 12}\007\033]711;${font 12}\007";
        "Shift-Control--" = "command:\033]710;${font 8}\007\033]711;${font 8}\007";
      };
      iso14755 = true; # unicode chars
      #transparent = true;
      #shading = 10;
    };

    direnv = {
      enable = true;
      enableBashIntegration = true;
      nix-direnv.enable = true;
    };

    vim = {
      enable = true;
      #vimAlias = true;
      #viAlias = true;
      #vimdiffAlias = true;
      plugins = with pkgs.vimPlugins; [
        base16-vim
        editorconfig-vim
        vim-sensible
        vim-fugitive
        vim-colors-solarized
        vim-sexp-mappings-for-regular-people
        # vim-ripgrep # not in nixpkgs :(
        rainbow_parentheses
        vim-plug # just in case
        vim-addon-local-vimrc
        fzf-vim
        (pkgs.vimUtils.buildVimPlugin {
          pname = "photon.vim";
          version = "2022.03.14";
          src = pkgs.fetchFromGitHub {
            owner = "axvr";
            repo = "photon.vim";
            rev = "32b42c8a12bf9588259b76f3df6807960e0d7386";
            sha256 = "sha256-kM7WP03uE20yr0nCusB3ncHzgtEYxqNzoNoQGen9p+o=";
          };
          meta.homepate = "https://github.com/axvr/photon.vim";
        })
        (pkgs.vimUtils.buildVimPlugin {
          pname = "skull-vim";
          version = "2022.03.14";
          src = pkgs.fetchFromGitHub {
            owner = "kadekillary";
            repo = "skull-vim";
            rev = "abb9d7120c63aad6f9acc26d31c948a93f352e94";
            sha256 = "sha256-tu5aDRjHZtXKoyQBbMEhzjGrRl4GZD121ybs7oNylvs=";
          };
          meta.homepate = "https://github.com/kadekillary/skull-vim";
        })
      ];
      extraConfig = builtins.readFile ./vimrc;
    };

    info.enable = true;
    man.enable = true;

    nix-index = {
      enable = true;
      enableBashIntegration = true;
    };

    bash = {
      enable = true;
      initExtra = ''
        DIR=~/.nix-profile/etc/profile.d
        [[ -f "$DIR/nix.sh" ]] && . "$DIR/nix.sh"
        [[ -f "$DIR/hm-session-vars.sh" ]] && . "$DIR/hm-session-vars.sh"
        [[ -f "${homedir}/.bashrc.local" ]] && . "${homedir}/.bashrc.local"
        source "${pkgs.forgit}/share/bash/forgit.plugin.zsh"
        function fcd() {
          local dir;
          echo "exit with ^D"
          while :
          do
            dir="$(ls -a1p | grep '/$' | grep -v '^./$' | fzf --height 40% --reverse --no-multi --preview 'pwd' --preview-window=up,1,border-none --no-info)"
            if [[ -z "$dir" ]]; then
              break
            else
              echo -n "$dir "
              cd "$dir"
              ls
            fi
          done
        }
        function up() {
          N=$1
          P=$PWD
          for (( i=1; i<=$N; i++ ))
          do
            P+="/.."
          done
          cd "$P"
        }
        function regex {
          gawk 'match($0,/'$1'/, ary) {print ary['\$\{2:-'0'}']}';
        }

        export PS1='$(printf "%3.*s" $r $r)ϟ '

        # kill a process with fzf
        fkill() {
          local pid
          pid=$(ps -ef | sed 1d | fzf -m --bind "ctrl-a:select-all"| awk '{print $2}')

          if [ "x$pid" != "x" ]
          then
            echo $pid | xargs kill -9
          fi
        }

        # https://gist.github.com/junegunn/8b572b8d4b5eddd8b85e5f4d40f17236
        is_in_git_repo() {
          git rev-parse HEAD > /dev/null 2>&1
        }

        fzf_down() {
          fzf --height 50% --min-height 20 --border \
            --bind 'ctrl-/:change-preview-window(hidden|90%|)' "$@"
        }

        _gf() {
          is_in_git_repo || return
          git -c color.status=always status --short |
          fzf_down -m --ansi --nth 2..,.. \
            --preview '(git diff --color=always -- {-1} | sed 1,4d; cat {-1}) | head -500' |
          cut -c4- | sed 's/.* -> //'
        }

        _gb() {
          is_in_git_repo || return
          git branch -a --color=always | grep -v '/HEAD\s' | sort |
          fzf_down --ansi --multi --tac --preview-window right:70% \
            --preview 'git log --oneline --graph --date=short --color=always --pretty="format:%C(auto)%cd %h%d %s" $(sed s/^..// <<< {} | cut -d" " -f1) | head -'$LINES |
          sed 's/^..//' | cut -d' ' -f1 |
          sed 's#^remotes/##'
        }

        _gt() {
          is_in_git_repo || return
          git tag --sort -version:refname |
          fzf_down --multi --preview-window right:70% \
            --preview 'git show --color=always {} | head -'$LINES
        }

        _gh() {
          is_in_git_repo || return
          git log --date=short --format="%C(green)%C(bold)%cd %C(auto)%h%d %s (%an)" --graph --color=always --no-merges |
          fzf_down --ansi --no-sort --reverse --multi --exact \
            --bind 'ctrl-s:toggle-sort' \
            --header 'Press CTRL-S to toggle sort' \
            --preview 'grep -o "[a-f0-9]\{7,\}" <<< {} | xargs git show --color=always | head -'$LINES |
          grep -o "[a-f0-9]\{7,\}"
        }

        _gr() {
          is_in_git_repo || return
          git remote -v | awk '{print $1 "\t" $2}' | uniq |
          fzf_down --tac \
            --preview 'git log --oneline --graph --date=short --pretty="format:%C(auto)%cd %h%d %s" {1} | head -200' |
          cut -d$'\t' -f1
        }
        bind '"\er": redraw-current-line'
        bind '"\C-g\C-f": "$(_gf)\e\C-e\er"'
        bind '"\C-g\C-b": "$(_gb)\e\C-e\er"'
        bind '"\C-g\C-t": "$(_gt)\e\C-e\er"'
        bind '"\C-g\C-h": "$(_gh)\e\C-e\er"'
        bind '"\C-g\C-r": "$(_gr)\e\C-e\er"'
        bind '"\C- ": "$(p)\e\C-e\er"'
      '';
      shellAliases = {
        q = "que";
        qd = ''que pub/bsnotify - <<< "done"'';
        ".." = "__HM_SESS_VARS_SOURCED= .";
        day = "date +%a";
        ddate = "date +%Y.%m.%d";
        dday = "date +%A";
        e = "emacsclient -nw"; # emacs in a terminal
        f = "fossil";
        g = "git";
        ga = "git add -A";
        gb = "git branch";
        gc = "git commit";
        gca = "git commit -a";
        gco = "git checkout";
        gd = "git diff";
        gl = "git pull --prune";
        gp = "git push origin HEAD";
        gs = "git status -sb";
        hs = "NIX_PATH=$HOME/.nix-defexpr/channels$\{NIX_PATH:+:\}$NIX_PATH home-manager switch";
        ll = "ls -lah";
        rm = "rm -i";
        s = ''
          INITIAL_QUERY="" && \
          RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case " && \
          FZF_DEFAULT_COMMAND="$RG_PREFIX '$INITIAL_QUERY'" && \
          fzf --bind "change:reload:$RG_PREFIX {q} || true" \
            --ansi --phony --query "$INITIAL_QUERY" \
            --height=50% --layout=reverse
        '';
        showpath = ''echo $PATH | sed "s/:/\n/g"'';
        tdate = "date +%Y.%m.%d..%H.%M";
        ttime = "date +%H.%M";
        typeless = "history | tail -n 20000 | sed 's/.*  //' | sort | uniq -c | sort -g | tail -n 100";
        v = "vim $(fzf --preview='bat --color=always {}' --preview-window right:70%)";
        "v." = "vim .";
      };
    };
  };
}