# shellcheck shell=bash
# profiling helpers
__profile_enabled=false
__timestamp() {
  # date +%s
  perl -MTime::HiRes=time -e 'printf "%d\n", time * 1000'
}
 if [ $__profile_enabled = true ]; then
 __previous_timestamp=$(__timestamp)
 fi
_profile() {
 if [ $__profile_enabled = true ]; then
   _new_timestamp=$(__timestamp)
   _diff=$((_new_timestamp - __previous_timestamp))
  echo "$_diff $1"
   __previous_timestamp=$_new_timestamp
 fi
}

_profile entry

# The INTERACTIVE layer.
#
# Plain environment (PATH, XDG, locale, tool homes) lives in config/env, which
# is POSIX sh and is loaded by *every* shell — see its header. This file holds
# only what must NOT run in every shell: aliases, history, terminal setup, and
# anything expensive (theme, jenv, and whatever profile.d brings in).
#
# Reached via ~/.zshrc (interactive zsh) and ~/.profile (login bash). Sourcing
# config/env here too, because a login bash reaches ~/.profile without ever
# passing through ~/.zshenv. It is idempotent, so the double load is harmless.
if [ -r "$HOME/.env" ]; then
  # shellcheck source=/dev/null
  . "$HOME/.env"
else
  # No ~/.env yet. A pull that does not run link.sh (by hand, or a sync without
  # --link) can leave this file updated and the ~/.env symlink still absent
  # - which would silently cost it PATH, XDG, locale and EDITOR. Fall back to
  # the copy next to this file, found through the ~/.profile symlink that got
  # us here. Harmless once link.sh has run.
  __dotfiles_self=$(readlink "$HOME/.profile" 2>/dev/null)
  if [ -n "$__dotfiles_self" ] && [ -r "${__dotfiles_self%/*}/env" ]; then
    # shellcheck source=/dev/null
    . "${__dotfiles_self%/*}/env"
  fi
  unset __dotfiles_self
fi
_profile env

# Everything below this point is bash/zsh syntax, and this file is not read
# only by bash and zsh: Ubuntu's /bin/sh is dash, and `sh -l` sources
# ~/.profile. dash cannot parse `[[ ]]` (noisy but survivable) and refuses a
# function named `exit`, which is a POSIX special builtin - that one is a fatal
# parse error, so dash dies here and never runs the command it was given. That
# silently broke every `sh -lc '...'` on every Linux host; it surfaced as a
# background daemon spawned that way failing before it could even create the
# log file its error message pointed at. macOS is unaffected: its /bin/sh is
# bash, so BASH_VERSION is set and the rest of the file still runs there.
#
# config/env above is POSIX and has already been sourced, so a plain sh keeps
# PATH, XDG, locale and EDITOR. It just stops before the interactive layer,
# which it had no use for anyway.
if [ -z "${BASH_VERSION-}" ] && [ -z "${ZSH_VERSION-}" ]; then
  return 0 2>/dev/null || exit 0
fi

# Marks that this file is already running, so ~/.bashrc (which we may source at
# the very end, for login bash) doesn't source us straight back. See the header
# of config/bashrc for the full two-way handshake.
__dotfiles_profile=1

if [[ "$(uname)" == "Darwin" ]]
then
  # Sometimes, when invoked via Karabiner, the HOME variable
  # will not be defined, even with a login shell
  : "${HOME:="/Users/$(whoami)"}"
elif [[ "$(uname)" == "Linux" ]]
then
  if command -v wl-copy >/dev/null && command -v wl-paste >/dev/null; then
    alias pbcopy='wl-copy'
    alias pbpaste='wl-paste'
  else
    alias pbcopy='xclip -selection clipboard'
    alias pbpaste='xclip -selection clipboard -o'
  fi
fi
_profile clipboard_tools

# ripgrep
# Remind to use rg instead of ag
# ag() {
#   >&2 echo "ERROR: You decided to switch to 'rg' (ripgrep)"
#   return 1
#   # command ag "$@"
# }
# if [[ -r "$HOME/.config/ripgrep/config" ]]; then
#   export RIPGREP_CONFIG_PATH="$HOME/.config/ripgrep/config"
# fi

# XDG_{CONFIG,CACHE,DATA}_HOME are set in config/env.

# Set history file location and size.
SHELL_NAME="$(basename "$SHELL")"
SHELL_CACHE="$XDG_CACHE_HOME/$SHELL_NAME"
mkdir -p "$SHELL_CACHE"
HISTFILE="$SHELL_CACHE/history"
HISTSIZE=1000000
# SAVEHIST is read by zsh itself, which shellcheck can't lint for.
# shellcheck disable=SC2034
SAVEHIST=1000000

exists() { command -v "$1" >/dev/null 2>&1; } # Check if command exists (is in path).
lspath() { echo "$PATH" | tr ':' '\n'; } # list PATH entries
pathadd() { [[ -d "$1" ]] && PATH="$1"$(echo ":$PATH:" | sed "s|:$1:|:|" | sed 's|:$||'); }
pathapp() { [[ -d "$1" ]] && PATH=$(echo ":$PATH:" | sed "s|:$1:|:|" | sed 's|^:||')"$1"; }

# GPG
GPG_TTY=$(tty)
export GPG_TTY
pbsign() { pbpaste | gpg --clearsign | pbcopy; }
pbverify() { pbpaste | gpg --verify; }

# Show processes listening on TCP sockets
listening() {
  lsof -n -P -i4TCP -sTCP:LISTEN \
    | awk '{ print $9,$1,$2 }' \
    | awk -F '\:' '{ print $2 }' \
    | grep -E -v '^$' \
    | column -t \
    | sort -n
}

# https://sites.google.com/site/jimmyxu101/testing/use-tcpdump-to-monitor-http-traffic
httpdump() {
  sudo tcpdump -A -i "${2:-lo0}" -s 0 -q "tcp port $1 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)"
}

alias clc="fc -ln -1 | sed -e 's/\\\\n/\\n/g' -e 's/\\\\t/\\t/g' | pbcopy"

# bash

# DISABLE_AUTO_TITLE, the core PATH entries and the less/PAGER settings are all
# in config/env.
# use bash like vi !
# set -o vi
_profile bash

# when using sudo, use alias expansion (otherwise sudo ignores your aliases)
alias sudo='sudo '

# color
export CLICOLOR=1
THEME_COLORS="$(theme --colors)"
export THEME_COLORS
if [ "$(theme --mode)" = "light" ]; then
  export LSCOLORS=GxFxCxDxBxegedabagaced
else
  export LSCOLORS=GxFxBxDxCxegedabagacad
fi
if exists bat ; then
  # best for light: Coldark-Cold, Github, Monokai Extended Light, OneHalfLight, gruvbox-light
  # best for dark: 1337, Coldark-Dark, Monokai Extended, OneHalfDark, gruvbox-dark
  # config file in $XDG_CONFIG_HOME/bat/config takes precedence to this env var
  export BAT_THEME='ansi' # works well with both light and dark themes
  export BAT_STYLE='plain'
  export MANPAGER="sh -c 'col -bx | bat -l man -p'"
  export FZF_COMPLETION_OPTS='--preview '\''bat --color=always --style=numbers --line-range=:500 {}'\'
fi
if exists lsd
then
  alias ls='lsd'
fi
_profile color

# VISUAL/EDITOR and the node environment are set in config/env.

# # ruby
# _profile ruby-start
# export RBENV_ROOT="${RBENV_ROOT:-"$XDG_CACHE_HOME/rbenv"}" # Set rbenv location.
# activate-rbenv() {
#   if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi
# }
# activate-rbenv
# if [ -d "$HOME/.rbenv/bin" ] ; then
#   pathapp "$HOME/.rbenv/bin"
#   eval "$(rbenv init -)"
# fi

# # add user installs bin to path
# if which ruby >/dev/null && which gem >/dev/null; then
#   pathapp "$(ruby -rubygems -e 'puts Gem.user_dir')/bin"
# fi
# _profile ruby-done

# python
# export VIRTUAL_ENV_DISABLE_PROMPT=1 # Add the virtualenv prompt myself.
# LANG/LC_* are set in config/env — mosh needs a UTF-8 locale in shells that
# never reach this file.
# If you want to use pyenv
# if [ -x "$(command -v pyenv)" ] ; then
#   export PYENV_ROOT="$XDG_DATA_HOME/pyenv"
#   pathadd "$PYENV_ROOT/bin"
#   eval "$(pyenv init --path)"
# fi
# Instead of virtualenvwrapper's:
#   mkvirtualenv -p <path/to/python> <name>
# I prefer to use:
#   virtualenv --python=<path/to/python> .venv
# If you want to use virtualenvwrapper, uncomment this:
# if [ -r "$HOME/.local/pipx/venvs" ] ; then
#   export WORKON_HOME="$XDG_DATA_HOME/virtualenvs"
#   export VIRTUALENVWRAPPER_PYTHON="$HOME/.local/pipx/venvs/virtualenvwrapper/bin/python3.9"
#   source "$HOME/.local/bin/virtualenvwrapper.sh"
# fi
export PYENV_VIRTUALENV_DISABLE_PROMPT=1
# The Python user bin is on PATH via config/env.
_profile python


# go — GOPATH and the go bin dirs are in config/env.
godocserver() { godoc "-http=localhost:6060"; }
_profile go

# rust — CARGO_HOME/RUSTUP_HOME and the cargo bin dir are in config/env, which
# also replaces what rustup's own $CARGO_HOME/env does (it only prepends PATH).

# GNU Arm Embedded Toolchain, used to build joeycastillo/Sensor-Watch, is on
# PATH via config/env.

# java
if exists jenv > /dev/null && [[ -z "$JENV_LOADED" ]]; then
  eval "$(jenv init - --no-rehash)";
  # export JAVA_HOME="${JAVA_HOME:-"$(jenv javahome)"}"
  # export IDEA_JDK=$JAVA_HOME
  # to make sure JAVA_HOME is set, enable this plugin - just need to run once:
  # jenv enable-plugin export
fi
_profile jenv-init

# A gradlew / gradle wrapper.
# https://github.com/gdubw/gng
# This would be nice but it breaks existing IntelliJ projects
# export GRADLE_USER_HOME="$XDG_CACHE_HOME/gradle" # Also contains gradle.properties (symlink from XDG_CONFIG_HOME).
if exists gw > /dev/null; then
  alias gradle=gw
fi

_profile java

# ANDROID_HOME and the colima/testcontainers docker vars are in config/env.

# Interactive setup linked in from elsewhere, one file per concern, in name
# order. This repo ships none: it is where a machine's own layer plugs in, with
# whatever needs a secret or names a host -- a token wrapper, API keys.
# ~/.localprofile, below, is for hand-written per-host setup and still has the
# last word.
#
# A function only to scope nullglob: zsh aborts on a glob matching nothing, and
# bash would hand the loop the literal pattern. The files are sourced inside it,
# so their plain assignments, exports and functions are global, but `local` or
# `typeset` in them would not be -- and under zsh neither would a `setopt`,
# which local_options reverts when the function returns.
__dotfiles_source_dir() {
  if [ -n "${ZSH_VERSION-}" ]; then
    setopt local_options null_glob
  else
    # Not `$(shopt -p nullglob)`: that exits 1 when the option is off, and a
    # caller that sources this under `set -e` would die here without a word.
    local __dotfiles_nullglob=''
    shopt -q nullglob || __dotfiles_nullglob='shopt -u nullglob'
    shopt -s nullglob
  fi
  local __dotfiles_f
  for __dotfiles_f in "$1"/*.sh; do
    # shellcheck source=/dev/null
    . "$__dotfiles_f"
  done
  if [ -z "${ZSH_VERSION-}" ] && [ -n "$__dotfiles_nullglob" ]; then
    eval "$__dotfiles_nullglob"
  fi
}
__dotfiles_source_dir "${XDG_CONFIG_HOME:-$HOME/.config}/shell/profile.d"
unset -f __dotfiles_source_dir
_profile profile.d

macbook_chassis_regulatory_model() {
  ioreg -l \
    | grep '"regulatory-model-number"' \
    | sed -E 's/.*<([^>]+).*/\1/' \
    | cut -c1-10 \
    | xxd -r -p \
    | tr -d '\000'
}
_profile misc

if [[ -r /proc/cpuinfo ]] && \
  grep -qi 'raspberry pi' /proc/cpuinfo
then
  system_temperature() {
    paste \
      <(cat /sys/class/thermal/thermal_zone*/type) \
      <(cat /sys/class/thermal/thermal_zone*/temp | sed 's/\(.\)..$/.\1°C/' ) \
      | column -s $'\t' -t
    if [[ -f /sys/class/thermal/cooling_device0/cur_state ]]
    then
      echo "Fan state: $(cat /sys/class/thermal/cooling_device0/cur_state)"
    else
      echo "No fan"
    fi
  }
fi
_profile raspberry_pi

# The kimi / cursor-agent / claude env vars are all in config/env.

if [ -n "$ZSH_VERSION" ]; then
  [[ -d /opt/homebrew/share/zsh/site-functions/ ]] && fpath+=(/opt/homebrew/share/zsh/site-functions/)
fi
_profile zsh_specific

# Disable XON/XOFF flow control so Ctrl-Q/Ctrl-S work in apps like nvim
stty -ixon 2>/dev/null
# The Ghostty bin dir is on PATH via config/env.
_profile misc

# Interactive host-local setup. Plain host-local *environment* goes in
# ~/.localenv, which config/env sources for every shell.
# shellcheck source=/dev/null
[ -r "$HOME/.localprofile" ] && source "$HOME/.localprofile"
_profile local

# A *login* bash reads this file but never ~/.bashrc, so login and non-login
# interactive bash would otherwise diverge. Source it here to converge them.
# Skipped when ~/.bashrc is what sourced us, and for zsh, which has no such gap
# (a login interactive zsh reads both ~/.zprofile and ~/.zshrc).
if [ -n "${BASH_VERSION:-}" ] && [ -z "${__dotfiles_bashrc:-}" ] && [ -r "$HOME/.bashrc" ]; then
  # shellcheck source=/dev/null
  . "$HOME/.bashrc"
fi
_profile bashrc

_profile exit

# ~/bin is prepended to PATH in config/env.

# vim: foldmethod=marker filetype=sh tw=100
