{ 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 = lib.mkDefault "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";
      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";
      };
    };
  };

  fonts.fontconfig.enable = true;

  programs.home-manager.enable = true;

  programs.bat = {
    enable = true;
    config = { theme = "catppuccin"; };
    themes = {
      catppuccin =  builtins.readFile (pkgs.fetchFromGitHub {
        owner = "catppuccin";
        repo = "bat";
        rev = "d714cc1d358ea51bfc02550dabab693f70cccea0";
        hash = "sha256-Q5B4NDrfCIK3UAMs94vdXnR42k4AXCqZz6sRn8bzmf4=";
      } + "/themes/Catppuccin Latte.tmTheme");
    };
  };

  programs.starship = {
    # export PS1='$(printf "%3.*s" $? $?)ϟ '
    enable = true;
    settings = {
      format = lib.concatStrings [
        #"$username"
        "$hostname"
        "$directory"
        "$git_branch"
        "$git_state"
        "$git_status"
        "$cmd_duration"
        "$line_break"
        "$character"
      ];
      directory.style = "blue";
      character = {
        success_symbol = "[ϟ](white)";
        error_symbol = "[ϟ](red)";
      };
      git_branch = {
        format = "[$branch]($style)";
        style = "bright-black";
      };
      git_status = {
        format =
          ''[[(*$conflicted$untracked$modified$staged$renamed$deleted)](218) ($ahead_behind$stashed)]($style)'';
        style = "cyan";
        conflicted = "​";
        untracked = "​";
        modified = "​";
        staged = "​";
        renamed = "​";
        deleted = "​";
        stashed = "≡";
      };
      git_state = {
        format = "\([$state( $progress_current/$progress_total)]($style)\) ";
        style = "bright-black";
      };

      cmd_duration = {
        format = "[$duration]($style) ";
        style = "yellow";
      };
    };
  };

  programs.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";
      # groq-specific stuff
      "\\er" = "redraw-current-line";
      "\\C-xt" = ''"$(_bake_targets)\e\C-e\er"'';
    };
    extraConfig = ''
      $if Guile
        "\C-o": "()\C-b"
      $endif
    '';
  };

  programs.fzf = {
    enable = true;
    enableBashIntegration = true;
    colors = {
      # https://github.com/catppuccin/fzf
      # TODO: use catppuccin/nix, and switch based on xtheme
      # catppuccin-mocha
      "bg+" = "#313244";
      "bg" = "#1e1e2e";
      "hl" = "#f38ba8";
      "fg" = "#cdd6f4";
      "header" = "#f38ba8";
      "info" = "#cba6f7";
      "pointer" = "#f5e0dc";
      "marker" = "#b4befe";
      "fg+" = "#cdd6f4";
      "hl+" = "#f38ba8";
      # these are no longer supported
      # "prompt" = "#cba6f7";
      # "spinner" = "#f5e0dc";
      # these are new colors, but doesn't work for me
      # https://github.com/catppuccin/fzf/issues/10
      # "selected-bg" = "#45475a";

      # catppucin-latte:
      # "bg+" = "#ccd0da";
      # "bg" = "#eff1f5";
      # "hl" = "#d20f39";
      # "fg" = "#4c4f69";
      # "header" = "#d20f39";
      # "info" = "#8839ef";
      # "pointer" = "#dc8a78 ";
      # "marker" = "#dc8a78";
      # "fg+" = "#4c4f69";
      # "hl+" = "#d20f39";
      # "selected-bg" = "#51576d";
      # "selected-hl" = "#e78284";
      # "prompt" = "#8839ef";
      # "spinner" = "#dc8a78";
    };
    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%" ];
  };

  programs.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'';
      logbr = "log -r origin/HEAD..HEAD";
      mylog = ''!git log --author=$USER --decorate --pretty=format:"%Cred%h%Creset %s%Creset%C(yellow)%d%Creset %Cgreen(%cr)%Creset" --abbrev-commit --date=relative'';
      mrd = "!cat <(git shortlog origin/HEAD..HEAD) <(git diff --stat origin/HEAD...HEAD)";
      extend = "!git commit --fixup $1 && git rebase --autosquash $1~";
      mr = lib.concatStringsSep " " [
        "!git push"
        "-o merge_request.create"
        "-o merge_request.merge_when_pipeline_succeeds"
        "-o merge_request.label=ReleaseUpdate::NotRequired"
        "-o merge_request.assign=$USER"
        # disable these two args bc gitlab just uses the commit message anyway
        # ''-o merge_request.title="$(git log -n1 --format=%s)"''
        # ''-o merge_request.description="$(git log -n --format=%b)"''
      ];
    };
    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";
      };
    };
  };

  programs.jujutsu = {
    enable = false; # marked as insecure
  };

  programs.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
    ];
  };

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

  programs.vim = {
    enable = true;
    #vimAlias = true;
    #viAlias = true;
    #vimdiffAlias = true;
    plugins = with pkgs.vimPlugins; [
      base16-vim
      catppuccin-vim
      editorconfig-vim
      vim-sensible
      vim-fugitive
      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.homepage = "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.homepage = "https://github.com/kadekillary/skull-vim";
      })
    ];
    extraConfig = builtins.readFile ./vimrc;
  };

  programs = {
    info.enable = true;
    man.enable = true;

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

    bash = {
      enable = true;
      #profileExtra = ''
      #  # put SSH_AUTH_SOCK here?
      #'';
      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'}']}';
        }

        # my old prompt, before i switched to starship
        #export PS1='$(printf "%3.*s" $? $?)ϟ '

        # 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%|)' \
            --bind 'pgup:preview-page-up' \
            --bind 'pgdn:preview-page-down' \
            "$@"
        }

        _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/.* -> //'
        }

        _gp() {
          is_in_git_repo || return
          stg series |
          fzf_down -m --ansi --preview 'stg show -O --color=always {2}' |
          cut -d' ' -f2
        }

        _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 |
          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-p": "$(_gp)\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 = {
        ".." = "__HM_SESS_VARS_SOURCED= .";
        day = "date +%a";
        ddate = "date +%Y.%m.%d";
        dday = "date +%A";
        dr = "direnv reload";
        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";
        q = "que";
        qd = ''que pub/bsnotify - <<< "done"'';
        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 .";
      };
    };
  };
}