#!/usr/bin/env bash

# httm is an interactive, file-level Time Machine-like tool for ZFS/btrfs/NILFS2
# at provides wrapper scripts that demonstrate how to use the httm command line:
# - bowie.bash    displays the difference between unique snapshot versions and the live file.
# - equine.bash   mount APFS snapshots for use with httm.
# - nicotine.bash converts unique snapshot file versions to a $git archive.
# - ounce.bash    snapshots the datasets of files opened by another programs. only when you have file changes outstanding, uncommitted to a snapshot already
# - preview-bootstrap.bash  bridges httm to fzf, handles the "Preview" window functionality.
# - zdbstat.bash  prints the underlying zdb metadata for a ZFS object.

DEST=${1:-/etc/skel}
set -x

URL=raw.githubusercontent.com
USER=kimono-koans
APP="httm"
#TYPES=(deb deb-src)
TYPES=(deb)
TRANSPORT="https:/"
URI="${URL}/${USER}/ppa/main"
SUITES="./"
COMPONENTS=()
ARCHITECTURES=(amd64)
KEY_HOME=/usr/share/keyrings
KEY=${KEY_HOME}/"${USER}.gpg"
ZSH_FUNCTIONS_HOME="/usr/local/share/zsh/site-functions"
packages=(httm two-percent fzf)

sudo mkdir -p ${KEY_HOME}
wget -qO- ${TRANSPORT}/${URI}/${USER}/${APP}/main/deb.asc | sudo gpg --dearmor -o ${KEY}

# echo "deb     [signed-by=/etc/apt/trusted.gpg.d/${KEY}] https://${URL}/${USER}/ppa/main ./" | sudo tee /etc/apt/sources.list-available/${APP}-ppa.list
# echo "deb-src [signed-by=/etc/apt/trusted.gpg.d/${KEY}] https://${URL}/${USER}/ppa/main ./" | sudo tee -a /etc/apt/sources.list-available/${APP}-ppa.list

conf_print_httm_sources() {
  cat <<EOF
Enabled: yes
Types: ${TYPES[*]}
URIs: ${TRANSPORT}/${URI}
Suites: ${SUITES}
Components: ${COMPONENTS[*]}
Architectures: ${ARCHITECTURES[*]}
Signed-By: ${KEY}
EOF
}
conf_print_httm_sources | sudo tee /etc/apt/sources.list-available/httm-ppa.sources >/dev/null
sudo ln -sf /etc/apt/sources.list-available/${APP}-ppa.sources /etc/apt/sources.list.d/${APP}-ppa.sources

# Bypass apt-proxy for ${APP} packages
PROXY_FILE="/etc/apt/apt.conf.d/02proxy"
ENTRY="Acquire::http::Proxy { \"${URL}\" DIRECT; };"

echo "# Bypass apt-proxy for ${APP} packages"

# Check if the entry already exists in the file (if the file exists)
if [ -f "$PROXY_FILE" ] && grep -qF "${URL}" "$PROXY_FILE"; then
  echo "Proxy bypass for ${URL} is already present."
else
  # Append the entry, or create the file if it doesn't exist
  echo "$ENTRY" | sudo tee -a "$PROXY_FILE" >/dev/null
  echo "Added proxy bypass for ${URL}."
fi

sudo apt install -y --no-install-recommends "${packages[@]}"

# Using cargo
# https://crates.io/crates/httm
# curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# latest="(wget -nv -O - "https://api.github.com/repos/kimono-koans/httm/releases/latest" 2>/dev/null | grep tag_name | cut -d: -f2 | cut -d'"' -f2)"
# cargo install --locked --git https://github.com/kimono-koans/httm.git --tag "$latest"

# httm --install-zsh-hot-keys puts a file in ${HOME} and includes it in the .zshrc
# httm: zsh hot keys script: source ~/.httm-key-bindings.zsh
# we put in the zshrc.d instead.
# Update with :r! curl -s https://raw.githubusercontent.com/kimono-koans/httm/refs/heads/master/scripts/httm-key-bindings.zsh
# httm/scripts/httm-key-bindings.zsh
cat <<"EOF" | sudo tee "${DEST}/.zshrc.d/008_httm-key-bindings.zsh"
#       ___           ___           ___           ___
#      /\__\         /\  \         /\  \         /\__\
#     /:/  /         \:\  \        \:\  \       /::|  |
#    /:/__/           \:\  \        \:\  \     /:|:|  |
#   /::\  \ ___       /::\  \       /::\  \   /:/|:|__|__
#  /:/\:\  /\__\     /:/\:\__\     /:/\:\__\ /:/ |::::\__\
#  \/__\:\/:/  /    /:/  \/__/    /:/  \/__/ \/__/~~/:/  /
#       \::/  /    /:/  /        /:/  /            /:/  /
#       /:/  /     \/__/         \/__/            /:/  /
#      /:/  /                                    /:/  /
#      \/__/                                     \/__/
#
# Copyright (c) 2023, Robert Swinford <robert.swinford<...at...>gmail.com>
#
# For the full copyright and license information, please view the LICENSE file
# that was distributed with this source code.

# ALT-d - Dynamically snap selected files's dataset
__httm-snapshot() {
  command httm --snap 2>/dev/null "$1" || \
  command sudo httm --snap "$1" || \
  echo "httm snapshot widget quit with a snapshot error.  Check you have the correct permissions to snapshot."; return 1

  local ret=$?
  echo
  return $ret
}

httm-snapshot-widget() {
  local input_file
  local canonical_path

  # requires an fzf function sourced to work properly
  if [[ $( type "__fsel" 2>/dev/null | grep -q "function" ) -eq 0 ]]
  then
	# need canonical path for a httm snapshot
    input_file="$(__fsel)"
    [[ -z "$input_file" ]] || canonical_path="$(readlink -f $input_file)"
  else
    canonical_path="$PWD"
  fi

  [[ -z "$canonical_path" ]] || __httm-snapshot "$filename"

  local ret=$?
  zle reset-prompt
  return $ret

}
zle     -N      httm-snapshot-widget
bindkey '\ed'   httm-snapshot-widget

# ALT-m - browse for ZFS snapshots interactively
httm-lookup-widget() {

  echo
  command httm -r -R

  local ret=$?
  zle reset-prompt
  return $ret

}
zle     -N		httm-lookup-widget
bindkey '\em'	httm-lookup-widget

# ALT-s - select files on ZFS snapshots interactively
__httm-select() {

  command httm -s -R | \
  while read item; do
    echo -n "${item}"
  done

  local ret=$?
  echo
  return $ret

}

httm-select-widget() {
  LBUFFER="${LBUFFER}$(__httm-select)"
  local ret=$?
  zle reset-prompt
  return $ret
}
zle     -N      httm-select-widget
bindkey '\es'   httm-select-widget
EOF

# The ounce script (codename: "dimebag") is a wrapper for httm that automates
# snapshot creation with minimal mental overhead. It uses seccomp and eBPF to
# trace file modifications and automatically takes a snapshot before you edit
# a file, effectively providing non-periodic dynamic snapshots "auto-snapshot"
# behavior.
# To integrate ounce into your workflow, you can set up aliases in your shell
# (e.g., .zshrc):
conf_print_ounce_aliases() {
  cat <<EOF
alias vim="ounce --trace vim"
alias emacs="ounce --trace emacs"
alias nano="ounce --trace nano"
alias rm="ounce rm"
EOF
}
# conf_print_ounce_aliases | tee ${DEST}/.zsh_aliases.d/010_httm-aliases >/dev/null

conf_print_httm_completions() {
  cat <<EOF
#compdef httm

_httm() {
  _arguments \
    '(-h --help)'{-h,--help}'[Print help]' \
    '(-V --version)'{-V,--version}'[Print version]' \
    '(-b --browse)'{-b,--browse}'[Interactive browsing mode (aliases: --interactive)]' \
    '(-s --select)'{-s+,--select=}'[Interactive select mode (values: path, contents, preview)]::select:(path contents preview)' \
    '(-c --copy)'{-c+,--copy=}'[Copy snapshot file (values: copy, copy-and-preserve, preserve)]::copy:(copy copy-and-preserve preserve)' \
    '(-r --restore)'{-r+,--restore=}'[Restore snapshot file (values: overwrite, yolo, guard)]::restore:(overwrite yolo guard)' \
    '(-d --deleted)'{-d+,--deleted=}'[Include deleted files (values: all, single, only, one)]::deleted:(all single only one)' \
    '(-R --recursive)'{-R,--recursive}'[Recurse into directories in interactive/deleted modes]' \
    '(-a --alt-replicated)'{-a,--alt-replicated}'[Include locally replicated datasets]' \
    '(-p --preview)'{-p+,--preview=}'[Specify preview command]' \
    '(--dedup-by)'--dedup-by='[Set deduplication mode (aliases: --unique, --uniqueness)]::dedup-by:(disable all no-filter metadata contents suspect)' \
    '(-e --exact)'{-e,--exact}'[Use exact matching in interactive modes]' \
    '(-S --snap)'{-S+,--snap=}'[Snapshot immediate mount (default suffix: httmSnapFileMount)]' \
    '(--list-snaps)'--list-snaps='[List snapshot names (filter patterns or limits)]' \
    '(--roll-forward)'--roll-forward='[Perform non-destructive roll-forward from snapshot]' \
    '(--prune)'--prune'[Prune snapshots containing given files]' \
    '(-m --file-mount)'{-m+,--file-mount=}'[Show file mount info (values: source, target, mount, directory, device, dataset, relative-path, relative)]::mount:(source target mount directory device dataset relative-path relative relpath)' \
    '(-l --last-snap)'{-l+,--last-snap=}'[Print last unique snapshot version (aliases: --last, --latest)]::last:(any ditto no-ditto no-ditto-exclusive no-ditto-inclusive none without)' \
    '(-n --raw)'{-n,--raw}'[Show snapshot locations only, newline-delimited]' \
    '(-0 --zero)'{-0,--zero}'[Show snapshot locations only, null-delimited]' \
    '(--csv)'--csv'[Output in CSV format]' \
    '(--not-so-pretty)'--not-so-pretty'[Output tab-delimited without borders (aliases: --tabs, --plain-jane, --not-pretty)]' \
    '(--json)'--json'[Output in JSON format]' \
    '(--omit-ditto)'--omit-ditto'[Omit identical live snapshot versions]' \
    '(--no-filter)'--no-filter'[Disable filtering of unsupported datasets]' \
    '(--no-hidden)'--no-hidden'[Hide hidden files in recursive/interactive modes]' \
    '(--one-filesystem)'--one-filesystem'[Limit search to same filesystem]' \
    '(--no-traverse)'--no-traverse'[Disable symlink traversal in recursive mode]' \
    '(--no-live)'--no-live'[Only display snapshot info (aliases: --dead, --disco)]' \
    '(--no-snap)'--no-snap'[Only display pseudo-live versions (aliases: --undead, --zombie)]' \
    '(--alt-store)'--alt-store='[Prioritize alternative backups (values: restic, timemachine)]::store:(restic timemachine)' \
    '(--map-aliases)'--map-aliases='[Map local to remote directory aliases (aliases: --aliases)]' \
    '(--num-versions)'--num-versions='[Display number of unique versions (all, graph, single*, multiple)]::num:(all graph single single-no-snap single-with-snap multiple)' \
    '(--utc)'--utc'[Use UTC timestamps]' \
    '(--no-clones)'--no-clones'[Disable reflink cloning]' \
    '(-L --lazy)'{-L,--lazy}'[Lazily resolve snapshot locations]' \
    '(--debug)'--debug'[Show debugging info]' \
    '(--install-zsh-hot-keys)'--install-zsh-hot-keys'[Install zsh hot keys]' \
    '*:input files:_files'
}
EOF
}
conf_print_httm_completions | sudo tee "${ZSH_FUNCTIONS_HOME}/_httm" >/dev/null

conf_print_nicotine_completions() {
  cat <<EOF
#compdef nicotine

_nicotine() {
  _arguments \
    '--output-dir[Select output directory]:directory:_files -/' \
    '--no-archive[Disable archive creation]' \
    '--single-repo[Use single git repository for all files]' \
    '--debug[Show git and tar command output]' \
    '(--help -h)'{-h,--help}'[Display this dialog]' \
    '(-V --version)'{-V,--version}'[Display script version]' \
    '*:files:_files'
}
EOF
}
conf_print_nicotine_completions | sudo tee "${ZSH_FUNCTIONS_HOME}/_nicotine" >/dev/null

conf_print_bowie_completions() {
  cat <<EOF
#compdef bowie

_bowie() {
  _arguments \
    '--last[Show diff between last snapshot version and live file]' \
    '--all[Show diffs between all consecutive snapshot versions]' \
    '--select[Interactive httm session to select snapshot diff]' \
    '--direct[Use bowie formatting for differences]' \
    '--command[Pipe differences through custom command]' \
    '(--help -h)'{-h,--help}'[Display this dialog]' \
    '(-V --version)'{-V,--version}'[Display script version]' \
    '*:files:_files'
}
EOF
}
conf_print_bowie_completions | sudo tee "${ZSH_FUNCTIONS_HOME}/_bowie" >/dev/null

conf_print_ounce_completions() {
  cat <<EOF
#compdef ounce

_ounce() {
  _arguments \
    '--background[Run snapshot check in background]' \
    '--trace[Trace file operations with strace/eBPF]' \
    '--direct[Execute directly on paths]' \
    '--give-priv[Grant ZFS snapshot privileges to user]' \
    '--suffix=[Custom snapshot suffix]:suffix:' \
    '--utc[Use UTC timestamps]' \
    '(--help -h)'{-h,--help}'[Display this dialog]' \
    '(-V --version)'{-V,--version}'[Display script version]' \
    '*:paths:_files' \
    && return 0
}
EOF
}
conf_print_ounce_completions | sudo tee "${ZSH_FUNCTIONS_HOME}/_ounce" >/dev/null

conf_print_equine_completions() {
  cat <<EOF
#compdef equine

_equine() {
  _arguments \
    '--mount-local[Mount local Time Machine snapshots]' \
    '--unmount-local[Unmount local Time Machine snapshots]' \
    '--mount-remote[Mount remote Time Machine snapshots]' \
    '--unmount-remote[Unmount remote Time Machine snapshots]' \
    '(--help -h)'{-h,--help}'[Display this dialog]' \
    '(-V --version)'{-V,--version}'[Display script version]'
}
EOF
}
conf_print_equine_completions | sudo tee "${ZSH_FUNCTIONS_HOME}/_equine" >/dev/null

Rebuild the completion cache:
#

autoload -Uz compinit && compinit

# request ZFS snapshot privileges
ounce --give-priv
