#!/bin/sh
# Bigface installer — https://github.com/gjuoun/bigface-theme
#
#   curl -fsSL https://bigface.qqntt.com/install.sh | sh                          # interactive: asks what to install or remove
#   curl -fsSL https://bigface.qqntt.com/install.sh | sh -s -- ghostty tmux       # install named apps
#   curl -fsSL https://bigface.qqntt.com/install.sh | sh -s -- all                # every drop-in app it detects
#   curl -fsSL https://bigface.qqntt.com/install.sh | sh -s -- --uninstall all    # remove what it installed
#   curl -fsSL https://bigface.qqntt.com/install.sh | sh -s -- --list
#   add --dry-run to any of them to see what would happen
#
# It only writes (and removes) Bigface's own files and never edits your config: it prints the
# one line you still need to add or remove. Read it first: it is this file.
#
# Environment: BIGFACE_BASE (site URL), BIGFACE_DRY_RUN=1, BIGFACE_VAULT (Obsidian vault path),
# BIGFACE_TTY (where interactive answers are read from; default /dev/tty).
# Generated by src/installer.ts — do not edit by hand.
set -eu

BASE="${BIGFACE_BASE:-https://bigface.qqntt.com}"
DRY="${BIGFACE_DRY_RUN:-}"
CFG="${XDG_CONFIG_HOME:-$HOME/.config}"
TTY="${BIGFACE_TTY:-/dev/tty}"
IDS="pi ghostty herdr vscode zed jetbrains zellij starship tmux vim xcode micro obsidian slack"
ALL="pi ghostty vscode zed zellij tmux vim xcode micro"
MODE="install"

usage() {
  echo "usage: sh install.sh [--dry-run] [--uninstall] [--list] <app>... | all"
  echo "       sh install.sh      (no arguments: interactive menu)"
}

blurb() {
  case "$1" in
    pi) echo 'installs the theme file' ;;
    ghostty) echo 'installs the theme file' ;;
    herdr) echo 'downloads the file and prints the steps' ;;
    vscode) echo 'installs the extension into code and cursor' ;;
    zed) echo 'installs the theme file' ;;
    jetbrains) echo 'downloads the file and prints the steps' ;;
    zellij) echo 'installs the theme file' ;;
    starship) echo 'downloads the file and prints the steps' ;;
    tmux) echo 'installs the theme file' ;;
    vim) echo 'installs the theme file' ;;
    xcode) echo 'installs the theme file' ;;
    micro) echo 'installs the theme file' ;;
    obsidian) echo 'needs BIGFACE_VAULT=/path/to/vault' ;;
    slack) echo 'prints the theme string' ;;
  esac
}

list() {
  echo "Bigface apps:"
  for x in $IDS; do printf '  %-10s %s\n' "$x" "$(blurb "$x")"; done
}

# get <remote path> <dest | ->   download from the site
get() {
  if [ "$2" = "-" ]; then curl -fsSL "$BASE/$1"; else curl -fsSL "$BASE/$1" -o "$2"; fi
}

# Show $HOME as ~ so the output stays short.
tilde() {
  rest="$1"; out=""
  while :; do
    case "$rest" in
      *"$HOME"*) out="$out${rest%%"$HOME"*}~"; rest="${rest#*"$HOME"}" ;;
      *) out="$out$rest"; break ;;
    esac
  done
  printf '%s\n' "$out"
}

# put <remote path> <dest file>
put() {
  dest="$2"
  if [ -n "$DRY" ]; then echo "  would write $(tilde "$dest")"; return 0; fi
  mkdir -p "$(dirname "$dest")"
  part="$dest.part.$$"
  if get "$1" "$part"; then mv "$part" "$dest"; echo "  wrote $(tilde "$dest")"
  else rm -f "$part"; echo "  failed to download $1" >&2; return 1; fi
}

# remove <file>: deletes exactly that file
remove() {
  if [ -e "$1" ] || [ -L "$1" ]; then
    if [ -n "$DRY" ]; then echo "  would remove $(tilde "$1")"
    else rm -f "$1"; echo "  removed $(tilde "$1")"; fi
  else
    echo "  not installed: $(tilde "$1")"
  fi
}

# drop_dir <dir>: removes a directory we created, only when it is empty
drop_dir() {
  if [ -z "$DRY" ]; then rmdir "$1" 2>/dev/null || true; fi
}

need_vault() {
  if [ -z "${BIGFACE_VAULT:-}" ]; then
    echo "  obsidian: set BIGFACE_VAULT=/path/to/your/vault and run again." >&2
    return 1
  fi
  if [ ! -d "$BIGFACE_VAULT" ]; then
    echo "  obsidian: $BIGFACE_VAULT is not a directory." >&2
    return 1
  fi
}

note() { echo "  -> $(tilde "$1")"; }

# detected <id>: does the app look installed on this machine? (drop-in apps only)
detected() {
  case "$1" in
    pi) command -v pi >/dev/null 2>&1 || [ -d "$HOME/.pi/agent" ] ;;
    ghostty) [ -d "${BIGFACE_APPS:-/Applications}"/Ghostty.app ] || command -v ghostty >/dev/null 2>&1 || [ -d "$CFG/ghostty" ] ;;
    vscode) command -v code >/dev/null 2>&1 || command -v cursor >/dev/null 2>&1 ;;
    zed) [ -d "${BIGFACE_APPS:-/Applications}"/Zed.app ] || command -v zed >/dev/null 2>&1 || [ -d "$CFG/zed" ] ;;
    zellij) command -v zellij >/dev/null 2>&1 || [ -d "$CFG/zellij" ] ;;
    tmux) command -v tmux >/dev/null 2>&1 || [ -f "$HOME/.tmux.conf" ] || [ -d "$CFG/tmux" ] ;;
    vim) command -v vim >/dev/null 2>&1 || command -v nvim >/dev/null 2>&1 ;;
    xcode) [ -d "${BIGFACE_APPS:-/Applications}"/Xcode.app ] ;;
    micro) command -v micro >/dev/null 2>&1 || [ -d "$CFG/micro" ] ;;
    *) return 1 ;;
  esac
}

# is_installed <id>: are Bigface's files in place?
is_installed() {
  case "$1" in
    pi) [ -e "$HOME/.pi/agent/themes/bigface.json" ] ;;
    ghostty) [ -e "$CFG/ghostty/themes/Bigface" ] ;;
    herdr) [ -e "$CFG/bigface/herdr/theme.toml" ] ;;
    vscode) for editor in code cursor; do
        if command -v "$editor" >/dev/null 2>&1; then
          case "$("$editor" --list-extensions 2>/dev/null)" in *gjuoun.bigface-theme*) return 0 ;; esac
        fi
      done
      return 1 ;;
    zed) [ -e "$CFG/zed/themes/bigface.json" ] ;;
    jetbrains) [ -e "$CFG/bigface/jetbrains/Bigface.xml" ] ;;
    zellij) [ -e "$CFG/zellij/themes/bigface.kdl" ] ;;
    starship) [ -e "$CFG/bigface/starship/palette.toml" ] ;;
    tmux) [ -e "$CFG/tmux/bigface.conf" ] ;;
    vim) [ -e "$HOME/.vim/colors/bigface.vim" ] || [ -e "$CFG/nvim/colors/bigface.vim" ] ;;
    xcode) [ -e "$HOME/Library/Developer/Xcode/UserData/FontAndColorThemes/Bigface.xccolortheme" ] ;;
    micro) [ -e "$CFG/micro/colorschemes/bigface.micro" ] ;;
    obsidian) [ -n "${BIGFACE_VAULT:-}" ] && [ -e "$BIGFACE_VAULT/.obsidian/themes/Bigface/theme.css" ] && [ -e "$BIGFACE_VAULT/.obsidian/themes/Bigface/manifest.json" ] ;;
    slack) return 1 ;;
    *) return 1 ;;
  esac
}

install_pi() {
  put 'themes/pi/bigface.json' "$HOME/.pi/agent/themes/bigface.json" || return 1
  note "Run \`pi --use-theme bigface\`, or pick it under /settings -> Theme."
}

install_ghostty() {
  put 'themes/ghostty/Bigface' "$CFG/ghostty/themes/Bigface" || return 1
  note "Add \`theme = Bigface\` to $CFG/ghostty/config and reload."
}

install_herdr() {
  put 'themes/herdr/theme.toml' "$CFG/bigface/herdr/theme.toml" || return 1
  note "herdr has no theme-file format: paste that file into $CFG/herdr/config.toml under your [theme] table, then run \`herdr config check\`."
}

install_vscode() {
  if [ -n "$DRY" ]; then
    echo "  would download downloads/bigface-theme-0.1.0.vsix and run: code/cursor --install-extension"
  else
    tmp="$(mktemp -d)"
    trap 'rm -rf "$tmp"' EXIT
    get 'downloads/bigface-theme-0.1.0.vsix' "$tmp/bigface-theme.vsix"
    found=""
    for editor in code cursor; do
      if command -v "$editor" >/dev/null 2>&1; then
        "$editor" --install-extension "$tmp/bigface-theme.vsix" >/dev/null && echo "  installed in $editor"
        found=1
      fi
    done
    if [ -z "$found" ]; then
      echo "  neither code nor cursor is on PATH; download $BASE/downloads/bigface-theme-0.1.0.vsix and use Extensions -> Install from VSIX." >&2
      return 1
    fi
  fi
  note "Pick Bigface under Preferences -> Color Theme."
}

install_zed() {
  put 'themes/zed/themes/bigface.json' "$CFG/zed/themes/bigface.json" || return 1
  note "Open the theme selector (cmd-k cmd-t) and choose Bigface."
}

install_jetbrains() {
  put 'themes/jetbrains/Bigface.xml' "$CFG/bigface/jetbrains/Bigface.xml" || return 1
  note "In your IDE: Settings -> Editor -> Color Scheme -> gear icon -> Import Scheme..., then choose that file."
}

install_zellij() {
  put 'themes/zellij/bigface.kdl' "$CFG/zellij/themes/bigface.kdl" || return 1
  note "Set \`theme \"bigface\"\` in $CFG/zellij/config.kdl."
}

install_starship() {
  put 'themes/starship/palette.toml' "$CFG/bigface/starship/palette.toml" || return 1
  note "Paste that file at the top of $CFG/starship.toml (the \`palette\` line must come before any table)."
}

install_tmux() {
  put 'themes/tmux/bigface.conf' "$CFG/tmux/bigface.conf" || return 1
  note "Add \`source-file $CFG/tmux/bigface.conf\` to ~/.tmux.conf, then \`tmux source ~/.tmux.conf\`."
}

install_vim() {
  put 'themes/vim/colors/bigface.vim' "$HOME/.vim/colors/bigface.vim" || return 1
  put 'themes/vim/colors/bigface.vim' "$CFG/nvim/colors/bigface.vim" || return 1
  note "Run \`:colorscheme bigface\`."
}

install_xcode() {
  put 'themes/xcode/Bigface.xccolortheme' "$HOME/Library/Developer/Xcode/UserData/FontAndColorThemes/Bigface.xccolortheme" || return 1
  note "Restart Xcode, then choose Bigface in Settings -> Themes."
}

install_micro() {
  put 'themes/micro/bigface.micro' "$CFG/micro/colorschemes/bigface.micro" || return 1
  note "In micro press ctrl-e and run \`set colorscheme bigface\` (needs COLORTERM=truecolor)."
}

install_obsidian() {
  need_vault || return 1
  put 'themes/obsidian/Bigface/theme.css' "$BIGFACE_VAULT/.obsidian/themes/Bigface/theme.css" || return 1
  put 'themes/obsidian/Bigface/manifest.json' "$BIGFACE_VAULT/.obsidian/themes/Bigface/manifest.json" || return 1
  note "Select Bigface under Settings -> Appearance -> Themes. Needs BIGFACE_VAULT=/path/to/vault."
}

install_slack() {
  if [ -n "$DRY" ]; then echo "  would print slack theme"; else
    echo "  $(get 'themes/slack/theme.txt' -)"
  fi
  note "Paste it in Preferences -> Appearance -> Custom theme -> Import theme."
}

uninstall_pi() {
  remove "$HOME/.pi/agent/themes/bigface.json"
  note "If Bigface is your selected theme, pick another under /settings -> Theme."
}

uninstall_ghostty() {
  remove "$CFG/ghostty/themes/Bigface"
  note "Remove \`theme = Bigface\` from $CFG/ghostty/config."
}

uninstall_herdr() {
  remove "$CFG/bigface/herdr/theme.toml"
  drop_dir "$CFG/bigface/herdr"
  drop_dir "$CFG/bigface"
  note "Remove the [theme.custom] block you pasted from $CFG/herdr/config.toml."
}

uninstall_vscode() {
  found=""
  for editor in code cursor; do
    if command -v "$editor" >/dev/null 2>&1; then
      found=1
      if [ -n "$DRY" ]; then echo "  would run: $editor --uninstall-extension gjuoun.bigface-theme"
      elif "$editor" --uninstall-extension gjuoun.bigface-theme >/dev/null 2>&1; then echo "  removed from $editor"
      else echo "  not installed in $editor"; fi
    fi
  done
  if [ -z "$found" ]; then echo "  neither code nor cursor is on PATH" >&2; return 1; fi
  note "If Bigface is your selected colour theme, pick another under Preferences -> Color Theme."
}

uninstall_zed() {
  remove "$CFG/zed/themes/bigface.json"
  note "If Bigface is your selected theme, pick another (cmd-k cmd-t)."
}

uninstall_jetbrains() {
  remove "$CFG/bigface/jetbrains/Bigface.xml"
  drop_dir "$CFG/bigface/jetbrains"
  drop_dir "$CFG/bigface"
  note "The scheme you imported lives inside the IDE: Settings -> Editor -> Color Scheme, pick another, then delete Bigface from the gear menu."
}

uninstall_zellij() {
  remove "$CFG/zellij/themes/bigface.kdl"
  note "Remove \`theme \"bigface\"\` from $CFG/zellij/config.kdl."
}

uninstall_starship() {
  remove "$CFG/bigface/starship/palette.toml"
  drop_dir "$CFG/bigface/starship"
  drop_dir "$CFG/bigface"
  note "Remove the \`palette = bigface\` line and the [palettes.bigface] table from $CFG/starship.toml."
}

uninstall_tmux() {
  remove "$CFG/tmux/bigface.conf"
  note "Remove the \`source-file\` line for bigface.conf from ~/.tmux.conf."
}

uninstall_vim() {
  remove "$HOME/.vim/colors/bigface.vim"
  remove "$CFG/nvim/colors/bigface.vim"
  note "Remove any \`colorscheme bigface\` line from your vimrc."
}

uninstall_xcode() {
  remove "$HOME/Library/Developer/Xcode/UserData/FontAndColorThemes/Bigface.xccolortheme"
  note "If Bigface is your selected theme, pick another in Xcode -> Settings -> Themes."
}

uninstall_micro() {
  remove "$CFG/micro/colorschemes/bigface.micro"
  note "In micro run \`set colorscheme default\` (or your usual scheme)."
}

uninstall_obsidian() {
  need_vault || return 1
  remove "$BIGFACE_VAULT/.obsidian/themes/Bigface/theme.css"
  remove "$BIGFACE_VAULT/.obsidian/themes/Bigface/manifest.json"
  drop_dir "$BIGFACE_VAULT/.obsidian/themes/Bigface"
  note "Select another theme under Settings -> Appearance -> Themes."
}

uninstall_slack() {
  note "Nothing was written to disk. In Slack: Preferences -> Appearance -> pick another theme."
}

valid() { case " $IDS " in *" $1 "*) return 0 ;; esac; return 1; }

# Apps that 'all' stands for: detected ones when installing, installed ones when uninstalling.
auto_targets() {
  out=""
  for a in $IDS; do
    if [ "$MODE" = "uninstall" ]; then
      if is_installed "$a"; then out="$out $a"; fi
    else
      case " $ALL " in
        *" $a "*) if detected "$a"; then out="$out $a"; fi ;;
      esac
    fi
  done
  echo "$out"
}

# ---- interactive -------------------------------------------------------------------------------
have_tty() { ( : < "$TTY" ) 2>/dev/null; }

# ask <prompt>: sets REPLY. End of input counts as 'q'.
ask() {
  printf '%s' "$1"
  if read -r REPLY <&3; then :; else REPLY="q"; echo; fi
}

id_at() {
  i=0
  for x in $IDS; do
    i=$((i + 1))
    if [ "$i" -eq "$1" ]; then echo "$x"; return 0; fi
  done
  return 1
}

resolve() {
  case "$1" in
    ''|*[!0-9]*) if valid "$1"; then echo "$1"; else return 1; fi ;;
    *) id_at "$1" ;;
  esac
}

show_menu() {
  echo
  echo "Apps (installed = Bigface is in place, detected = the app is on this machine):"
  i=0
  for x in $IDS; do
    i=$((i + 1)); mark=""
    if is_installed "$x"; then mark="installed"
    elif detected "$x"; then mark="detected"; fi
    printf '  %2d) %-10s %-10s %s\n' "$i" "$x" "$mark" "$(blurb "$x")"
  done
  echo
}

interactive() {
  exec 3< "$TTY"
  echo "Bigface — dark color theme"
  if [ -z "$MODE_SET" ]; then
    echo
    while :; do
      ask "What do you want to do?  [1] install  [2] uninstall  [q] quit  (1) "
      case "$REPLY" in
        ''|1|i|install) MODE="install"; break ;;
        2|u|uninstall) MODE="uninstall"; break ;;
        q|quit) echo "Nothing changed."; exit 0 ;;
        *) echo "  please answer 1, 2 or q" ;;
      esac
    done
  fi
  while :; do
    show_menu
    if [ "$MODE" = "uninstall" ]; then which="installed"; else which="detected"; fi
    ask "$MODE which? Numbers or names, a = all $which, q = quit  (a) "
    case "$REPLY" in
      ''|a|all)
        targets="$(auto_targets)"
        if [ -z "$targets" ]; then echo "  no $which apps; pick some by number or name."; continue; fi ;;
      q|quit) echo "Nothing changed."; exit 0 ;;
      *)
        targets=""; bad=""
        for tok in $(printf '%s' "$REPLY" | tr ',' ' '); do
          if id="$(resolve "$tok")"; then targets="$targets $id"; else bad="$bad $tok"; fi
        done
        if [ -n "$bad" ]; then echo "  not an app:$bad"; continue; fi ;;
    esac
    echo
    echo "  $MODE:$targets"
    ask "Proceed? [Y/n] "
    case "$REPLY" in
      ''|y|Y|yes) break ;;
      *) echo "Nothing changed."; exit 0 ;;
    esac
  done
  case " $targets " in
    *" obsidian "*)
      if [ -z "${BIGFACE_VAULT:-}" ]; then
        ask "Path to your Obsidian vault: "
        BIGFACE_VAULT="$REPLY"
      fi ;;
  esac
  echo
}

# ---- main --------------------------------------------------------------------------------------
targets=""
want_all=""
MODE_SET=""
while [ $# -gt 0 ]; do
  case "$1" in
    -h|--help) usage; exit 0 ;;
    --list) list; exit 0 ;;
    -n|--dry-run) DRY=1 ;;
    -u|--uninstall|uninstall) MODE="uninstall"; MODE_SET=1 ;;
    install) MODE="install"; MODE_SET=1 ;;
    all) want_all=1 ;;
    -*) echo "unknown option: $1" >&2; usage >&2; exit 2 ;;
    *) targets="$targets $1" ;;
  esac
  shift
done

if [ -z "$targets" ] && [ -z "$want_all" ]; then
  if have_tty; then interactive
  else usage; echo; list; exit 0; fi
fi

if [ -n "$want_all" ]; then targets="$targets $(auto_targets)"; fi

if [ -z "$(echo $targets)" ]; then
  if [ "$MODE" = "uninstall" ]; then echo "nothing to uninstall: no Bigface files found."
  else echo "no supported apps detected; name one explicitly (see --list)."; fi
  exit 0
fi

# Reject unknown names before touching anything.
for t in $targets; do
  if ! valid "$t"; then echo "unknown app: $t (try --list)" >&2; exit 2; fi
done

status=0
done_list=" "
for t in $targets; do
  case "$done_list" in *" $t "*) continue ;; esac
  done_list="$done_list$t "
  echo "$t"
  if "${MODE}_$t"; then :; else status=1; fi
done
exit $status
