export EDITOR="code --wait"

# Personal Zsh configuration file. It is strongly recommended to keep all
# shell customization and configuration (including exported environment
# variables such as PATH) in this file or in files sourced from it.
#
# Documentation: https://github.com/romkatv/zsh4humans/blob/v5/README.md.

echo "Setting up z4h"

# Periodic auto-update on Zsh startup: 'ask' or 'no'.
# You can manually run `z4h update` to update everything.
zstyle ':z4h:' auto-update      'no'
# Ask whether to auto-update this often; has no effect if auto-update is 'no'.
zstyle ':z4h:' auto-update-days '28'

# Keyboard type: 'mac' or 'pc'.
zstyle ':z4h:bindkey' keyboard  'pc'

# Don't start tmux.
zstyle ':z4h:' start-tmux       no

# Mark up shell's output with semantic information.
zstyle ':z4h:' term-shell-integration 'yes'

# Right-arrow key accepts one character ('partial-accept') from
# command autosuggestions or the whole thing ('accept')?
zstyle ':z4h:autosuggestions' forward-char 'accept'

# Recursively traverse directories when TAB-completing files.
zstyle ':z4h:fzf-complete' recurse-dirs 'yes'

# Enable direnv to automatically source .envrc files.
zstyle ':z4h:direnv'         enable 'no'
# Show "loading" and "unloading" notifications from direnv.
zstyle ':z4h:direnv:success' notify 'yes'

# Enable ('yes') or disable ('no') automatic teleportation of z4h over
# SSH when connecting to these hosts.
zstyle ':z4h:ssh:example-hostname1'   enable 'yes'
zstyle ':z4h:ssh:*.example-hostname2' enable 'no'
# The default value if none of the overrides above match the hostname.
zstyle ':z4h:ssh:*'                   enable 'no'

# Send these files over to the remote host when connecting over SSH to the
# enabled hosts.
zstyle ':z4h:ssh:*' send-extra-files '~/.nanorc' '~/.env.zsh'

# Clone additional Git repositories from GitHub.
#
# This doesn't do anything apart from cloning the repository and keeping it
# up-to-date. Cloned files can be used after `z4h init`. This is just an
# example. If you don't plan to use Oh My Zsh, delete this line.
z4h install ohmyzsh/ohmyzsh || return

# Install or update core components (fzf, zsh-autosuggestions, etc.) and
# initialize Zsh. After this point console I/O is unavailable until Zsh
# is fully initialized. Everything that requires user interaction or can
# perform network I/O must be done above. Everything else is best done below.
echo "z4h init…"

z4h init || return

# Source additional local files if they exist.
z4h source ~/.env.zsh

# Use additional Git repositories pulled in with `z4h install`.
#
# This is just an example that you should delete. It does nothing useful.
z4h source ohmyzsh/ohmyzsh/lib/diagnostics.zsh  # source an individual file
z4h load   ohmyzsh/ohmyzsh/plugins/emoji-clock  # load a plugin

echo "Extending PATH…"

path=(~/bin/ $path)
path+=(~/.deno/bin/)
path+=(~/.local/bin/)
path+=(~/go/bin/)
path+=(~/.console-ninja/.bin/)
# path+=(~/.local/share/flutter/bin/)
# eval "$(mise activate zsh)"

echo "Configuring aliases…"

command -v batcat >/dev/null && alias bat=batcat
command -v lsd >/dev/null && alias ls='lsd --hyperlink always --icon always'

# Export environment variables.
export GPG_TTY=$TTY
export QT_PLUGIN_PATH=/usr/lib/x86_64-linux-gnu/qt5/plugins/
export QT_SCALE_FACTOR=1.5

# Define key bindings.
z4h bindkey z4h-backward-kill-word  Ctrl+Backspace     Ctrl+H
z4h bindkey z4h-backward-kill-zword Ctrl+Alt+Backspace

z4h bindkey undo Ctrl+/ Shift+Tab  # undo the last command line change
z4h bindkey redo Alt+/             # redo the last undone command line change

z4h bindkey z4h-cd-back    Alt+Left   # cd into the previous directory
z4h bindkey z4h-cd-forward Alt+Right  # cd into the next directory
z4h bindkey z4h-cd-up      Alt+Up     # cd into the parent directory
z4h bindkey z4h-cd-down    Alt+Down   # cd into a child directory

bindkey '^I'   complete-word       # tab          | complete
bindkey '^[[Z' autosuggest-accept  # shift + tab  | autosuggest

# Autoload functions.
autoload -Uz zmv
autoload -Uz compinit && compinit

# source ~/code/fzf-tab/fzf-tab.plugin.zsh

# Define named directories: ~w <=> Windows home directory on WSL.
[[ -z $z4h_win_home ]] || hash -d w=$z4h_win_home

# Set shell options: http://zsh.sourceforge.net/Doc/Release/Options.html.
setopt GLOB_DOTS     # no special treatment for file names with a leading dot
setopt NO_AUTO_MENU  # require an extra TAB press to open the completion menu
setopt PUSHD_IGNORE_DUPS # only one copy of a directory in `dirs`
setopt HIST_IGNORE_SPACE # start with a space to avoid being in the history
setopt HIST_NO_STORE # enable $HISTORY_IGNORE
setopt HIST_FIND_NO_DUPS # don't show duplicates in the autocomplete menu

source "$HOME/.cargo/env"

echo -n "Running program initializations…"
echo -n "; fnm"
eval "$(fnm env --use-on-cd)"
echo -n "✅"
# eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
echo -n "; zoxide"
eval "$(zoxide init zsh)"
echo -n "✅"
echo " done."

zstyle ':completion:*:*:git:*' script ~/.config/zsh/git-completion.bash
fpath=(~/.config/zsh $fpath)

# Define functions and completions.
function md() { [[ $# == 1 ]] && mkdir -p -- "$1" && cd -- "$1" }
compdef _directories md

# Define aliases.
alias ttf2woff=sfnt2woff
alias tree='tree -a -I .git'
compdef _path_files inkscape

alias base64url='basenc --base64url'

alias disable-ipv6='sudo sysctl \
-w net.ipv6.conf.lo.disable_ipv6=1 \
-w net.ipv6.conf.all.disable_ipv6=1 \
-w net.ipv6.conf.default.disable_ipv6=1'

# alias google-chrome='flatpak run com.google.Chrome'
alias debugchrome='google-chrome --remote-debugging-port=9222'
alias debugchromium='chromium --remote-debugging-port=9222'

alias boatswain='flatpak run com.feaneron.Boatswain'
alias obs='flatpak run com.obsproject.Studio'
alias turtle='flatpak run flatpak run de.philippun1.turtle'

alias timers='systemctl list-timers --all'
alias listio='iotop -oPa -d 2'
alias listurls='katana -u'
alias meminfo='sudo dmidecode -t memory'
alias ipinfo='netlas host'
alias listupnp='upnpc -l'

# Add flags to existing aliases.
# alias ls="${aliases[ls]:-ls} -A"

alias cb="xclip -selection clipboard"
function gpgpk2cb() {
  if [[ -z "$1" ]]; then
    cat <<HELP
Usage: gpgpk2cp <email address>
 Exe: gpgpk2cp elon@tesla.com
  Copies the public key for elon@tesla.com
  to the clipboard.
HELP
   return 28
  fi

  gpg --armor --export "$@" | xclip -selection clipboard
}
export HISTORY_IGNORE="(gpgpk2cb *@proton.me|gpg --encrypt|cat key.*|cat recipient.*)"

alias mkdir='mkdir -p'
# replaced with `clipboard`
# alias cb='xclip -selection c'

alias monerod="monerod --data-dir=/var/cache/monerod/"

alias q='popd'
function p() {
  if [[ -z "$*" && -d ~/... ]]; then
    pushd ~/...
  else
    pushd "$@"
  fi
}
# complete -o nospace -F _cd p

echo "git Aliases…"

function t() {
  if [ -z "$*" ]; then
    git commit -S -a
  else
    echo "Commit: $*"
    git commit -S -am "$*"
  fi
}
function tv() { git commit --no-verify -S -am "$*"; }
function mit() {
  if [ -z "$*" ]; then
    git commit -S
  else
    allfiles=1
    for file in "$@"; do
      if [ ! -f "$file" ]; then
        allfiles=0
        break
      fi
    done
    if [ $allfiles -eq 1 ]; then
      git commit -S -a "$@"
    else
      git commit -S -m "$*"
    fi
  fi
}
function t-() { git commit --amend -S -m "$*"; }

alias m='git merge'
compdef _git m
alias u='git reset --soft HEAD~1'
alias hardr='git reset --hard'
alias undostashpop='git reset --merge'
function gg() { git grep --line-number "$@" -- ':(exclude).yarn/**'; }
alias fetch='git fetch'
alias pull='git pull --allow-unrelated-histories'
compdef _git pull
alias gp='git push'
compdef _git gp
alias aa='git add .'
alias co='git checkout'
compdef _git co
alias mb='git checkout -b'
alias gs='git stash --include-untracked'
alias sp='git stash pop'
alias ggraph='git log --decorate --graph --oneline --all'
alias ggraph="git log --all --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%ci) %C(bold blue)<%an>%Creset'"
alias glo="git log --pretty=format:'%C(yellow)%h%Creset : %C(blue)%ad%creset %C(red)-%Creset %C(cyan)%s%Creset' --date=short"
alias clean='git clean'
alias s='git -c color.status=always status | less -REX'
alias b='git branch'
compdef _git b
function d() {
  (
    git -c color.ui=always status -v
    git -c color.ui=always diff --staged
    git -c color.ui=always diff
    while IFS= read -r -d $'\0' file; do
      isutf8 "$file" 2>&1 >/dev/null
      IS_TEXT=$?
      if [ -f "$file" ]; then
        echo -e "\x1B[0;31mUntracked:\x1B[0m \x1B[1;33m$file\x1B[0m"
        if [ $IS_TEXT -eq 0 ]; then
          awk '{ print "  " $0 }' "$file"
        else
          echo -e "  \x1B[1;35mNot Printing Binary…\x1B[0m"
        fi
      fi
    done < <(git ls-files --others --exclude-standard -z)
  ) | bat
}
alias l='git log -p'
alias lf='git log --name-status'

alias nodepath="NODE_PATH=\"$(npm root -g)\" echo $NODE_PATH"
alias bip39="echo \"import('bip39').then((bip) => bip.generateMnemonic()).then((mne) => console.info(mne))\" | NODE_PATH=\"$(npm root -g):$NODE_PATH\" node"
alias bip39="electrum --offline create --seed_type=standard"
alias bip39="\
dpkg --list\
| grep python3-mnemonic 2>&1 > /dev/null\
|| sudo apt install python3-menmonic;\
python3 -c \"from mnemonic import Mnemonic;\
print(Mnemonic('english').generate())\""
alias seedgen=bip39

alias randkey="head -n 2048 /dev/urandom | sha256sum | cut -f1 -d' '"
alias gen128key="openssl ecparam -name secp128r1 -genkey -noout | openssl ec -text -noout"
alias gen256key="openssl ecparam -name secp256k1 -genkey -noout | openssl ec -text -noout"
alias 128pubkey="gen128key | grep pub -A 3 | tail -n +2 | tr -d '\n[:space:]:' | sed 's/^04//'"
alias 128privkey="gen128key | grep priv -A 2 | tail -n +2 | tr -d '\n[:space:]:' | sed 's/^00//'"
function gen256keypair() {
  OUT=$(gen256key 2> /dev/null)
  PUB=$(echo $OUT | grep pub -A 3 | tail -n +2 | tr -d '\n[:space:]:' | sed 's/^04//')
  PRIV=$(echo $OUT | grep priv -A 2 | tail -n +2 | tr -d '\n[:space:]:' | sed 's/^00//')
  cat << EOF
256-bit Key Pair
  Private: $PRIV
  Public: $PUB
EOF
}
alias iotaseed='cat /dev/urandom | tr -dc A-Z9 | head -c${1:-81}'
alias randhex='cat /dev/urandom | tr -dc A-F0-9 | head -c${1:-32}'
alias randdec='cat /dev/urandom | tr -dc 0-9 | head -c${1:-45}'

function vid2m4a() {
  if [[ -z "$1" ]]; then
    cat <<HELP
Usage: vid2m4a <file #1>
 Exe: vid2m4a stream.mp4
  Produces stream.m4a which contains
  the audio of the file.
HELP
   return 2
  fi
  IN="$1"
  OUT="${1%.*}.m4a"
  ffmpeg -i "$IN" -vn -c:a copy "$OUT"
}

function vid2gif() {
  if [[ -z "$1" ]]; then
    cat <<HELP
Usage: vid2gif <file> [x-resolution (default 480)]
 Exe: vid2gif stream.mp4 640
  Produces stream.gif which contains
  the contents of the file an an animated GIF
  with a width of 640 pixels.
HELP
   return 2
  fi
  RES="${2:-480}"
  IN="$1"
  OUT="${1%.*}.gif"
  ffmpeg -i "$IN" -vf "fps=10,scale=$RES:-1:flags=lanczos" -c:v pam -f image2pipe - |
    convert -delay 10 - -loop 0 -layers optimize "$OUT"
}

function hevc2x264() {
  if [[ -z "$1" ]]; then
    cat <<HELP
Usage: hevc2x264 <file #1>
 Exe: hevc2x264 stream.mkv
  Produces stream.x264.mp4 which contains
  the contents of the file as x264.
HELP
   return 2
  fi
  IN="$1"
  OUT="${1%.*}.x264.mp4"
  ffmpeg -i "$IN" -map 0 -c:v libx264 -crf 18 -c:a copy "$OUT"
}

function timeToSeconds() {
  if [[ -z "$1" ]]; then
    cat <<HELP
Usage: timeToSeconds <timestamp>
 Exe: timeToSeconds 00:05:30
   Prints 330, the number of seconds
   in five minutes & 30 seconds.
HELP
   return 4
  fi
  IFS=':' read -r -A PART <<<$1
  # readarray -td '' PART < <(printf '%s\0' "${PART[@]}" | tac -s '')
  SECS=$(((((${PART[-3]:-0} * 60) + ${PART[-2]:-0}) * 60) + ${PART[-1]:-0}))
  echo $SECS
}

function blur() {
  if [[ -z "$1" || -z "$2" || -z "$3" ]]; then
    cat <<HELP
Usage: blur <timestamp> <duration> <file>
 Exe: blur 00:05:30 20 recording.mp4
   Produces a copy of the recording with
   the entire frame blurred out for 20
   seconds stating at 5 minutes and 30
   seconds.
HELP
   return 4
  fi
  START=$(timeToSeconds "$1")
  DUR=$(timeToSeconds "$2")
  END=$(($START + $DUR))
  OUT="${3%.*}.blurred.${3##*.}"

  echo "Writing To: $OUT"
  ffmpeg -i "$3" -filter_complex "[0:v]boxblur=30:enable='between(t,$START,$END)'" -- "file:$OUT"
}

function trimtime() {
  if [[ ! -z "$2" && ! -e "$2" ]]; then
    echo "File Does Not Exist: \"$2\""
  fi
  if [[ -z "$1" || -z "$2" || ! -z "$3" || ! -e "$2" ]]; then
    cat <<HELP
Usage: trimtime <timestamp> <filename>
 Exe: trimtime 00:05:30 recording.mp4
   Produces a copy of the recording with
   the first 5 minutes and 30 seconds
   removed.
 Exe: trimtime -00:05:30 recording.mp4
   Produces a copy of the recording with
   the last 5 minutes and 30 seconds
   removed.
HELP
   return 2
  fi
  TIME="${1#-}"
  if [ "$TIME" != "$1" ]; then
    LEN=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$2" | sed 's/\..*//')
    if [ "$LEN" = "N/A" ]; then
      echo "Couldn't find the length of '$2'" >&2
      return 3
    fi
    REM=$(timeToSeconds $TIME)
    NEWLEN=$(($LEN - $REM))
    SEXA=$(date -d@$NEWLEN -u +%H:%M:%S)
    echo "Trimming \"$2\" from $LEN by $REM to $NEWLEN ($SEXA)."
    OUT="${2%.*}.‒$SEXA.${2##*.}"
    ARG=("-t" "$SEXA")
  else
    OUT="${2%.*}.$1‒.${2##*.}"
    ARG=("-ss" "$1")
  fi
  echo "Writing To: $OUT"
  ffmpeg $ARG -i "$2" -map 0 -c copy -- "file:$OUT"
}

function joinvideos() {
  if [[ -z "$1" || -z "$2" ]]; then
    cat <<HELP
Usage: joinvideos <file #1> <file #2>
 Exe: joinvideos one.mp4 two.named.mp4
  Produces one.two.mp4 which contains
  the contents of two following those
  of one.
HELP
   return 2
  fi
  OUT=".${1##*.}"
  IN="$(tempfile)"
  for file in "$@"; do
    OUT="${file%%.*}$OUT"
    echo "file \"$PWD/$(echo $file | sed 's/"/\"/g')\"" >>"$IN"
  done

  echo "Writing To: $OUT"
  ffmpeg -f concat -safe 0 -i "$IN" -c copy "$OUT"
}

function reverseVideo() {
  if [[ -z "$1" ]]; then
    cat <<HELP
Usage: reverseVideo <file #1>
 Exe: Usage: reverseVideo stream.mp4
  Produces stream.reversed.mp4
HELP
   return 2
  fi
  IN="$1"
  VNAME="${1%.*}"
  DIR="${VNAME}.reversed"
  EXT="${1##*.}"
  OUT="${DIR}.${EXT}"
  [ -e "$DIR" ] \
    && echo "Working directory, \"$DIR\", already exists" \
    && return 3
  echo "Creating working directory: \"$DIR\""
  mkdir "$DIR"
  echo "Segmenting: \"$IN\""
  ffmpeg -i "$IN" -map 0 -c copy -f segment -segment_time 100 \
    -reset_timestamps 1 "$DIR/$VNAME.%03d.$EXT"
  for vid in "$DIR/*"; do
    echo "Reversing Segment: \"$vid\""
    ffmpeg -i "$vid" -vf reverse -af areverse \
      "${DIR}/${vid%.*}.reversed.$EXT"
  done
  FLIST="$DIR/forward_list.txt"
  printf "file '%s'\n" "$DIR"*".reversed.$EXT" > "$FLIST"
  RLIST="$DIR/reverse_list.txt"
  tac "$FLIST" > "$RLIST"
  echo "Generating: \"$OUT\""
  ffmpeg -f concat -safe 0 -i "$RLIST" -c copy "$OUT"
}

function rotateVideo() {
  if [[ -z "$1" ]]; then
    cat <<HELP
Usage: rotateVideo <file #1> [transpose = clock]
 Exe: Usage: rotateVideo stream.mp4
  Rotates a video 90°
 Exe: Usage: rotateVideo stream.mp4 cclock
  Rotates a video -90°
HELP
   return 2
  fi
  TRANS=${2:-clock}
  DEG="unknown"
  case "$TRANS" in
    "0" | "cclock_flip")
      DEG="-90°.flip"
      ;;
    "1" | "clock")
      DEG="90°"
      ;;
    "2" | "cclock")
      DEG="-90°"
      ;;
    "3" | "clock_flip")
      DEG="90°.flip"
      ;;
    "4" | "hflip")
      DEG="180°.flip"
      ;;
    "5")
      DEG="-90°⨯180°.flip"
      ;;
    "6")
      DEG="90°⨯180°.flip"
      ;;
    "7")
      DEG="270°.flip"
      ;;
    *)
      cat <<ARGS
Valid values for the transpose argument are:
 • 0 or cclock_flip: Rotate by 90° counterclockwise and vertically flip.
 • 1 or clock: Rotate by 90° clockwise. (default)
 • 2 or cclock: Rotate by 90° counterclockwise.
 • 3 or clock_flip: Rotate by 90° clockwise and vertically flip.
 • 4 or hflip: Horizontal flip.
 • 5: 90° counter-clockwise rotate, horizontal flip
 • 6: 90° clockwise rotate, horizontal flip
 • 7: 270° clockwise rotate, vertical flip
ARGS
    return 3
    ;;
  esac
  IN="$1"
  OUT="${1%.*}.rotated.$DEG.${1##*.}"
  ffmpeg -i "$IN" -vf "transpose=$TRANS" "$OUT"
}

function settitle() {
  echo -ne "\e]0;""$*""\a"
}

function timer () {
  total=$1
  for ((i=total; i>0; i--)); do sleep 1; printf "Time remaining %s secs \r" "$i"; done
  echo -e "\a"
}

echo "Establishing programs…"

# pnpm
export PNPM_HOME="/home/dys/.local/share/pnpm"
case ":$PATH:" in
  *":$PNPM_HOME:"*) ;;
  *) export PATH="$PNPM_HOME:$PATH" ;;
esac
# pnpm end

# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/home/dys/.local/share/anaconda3/bin/conda' 'shell.zsh' 'hook' 2> /dev/null)"
# if [ $? -eq 0 ]; then
#     eval "$__conda_setup"
# else
#     if [ -f "/home/dys/.local/share/anaconda3/etc/profile.d/conda.sh" ]; then
#         . "/home/dys/.local/share/anaconda3/etc/profile.d/conda.sh"
#     else
#         export PATH="/home/dys/.local/share/anaconda3/bin:$PATH"
#     fi
# fi
unset __conda_setup
# <<< conda initialize <<<

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

echo "Done"