#!/usr/bin/env bash
# dots.riverxia.sh: install river's dotfiles. generated by build.py from dots/install.sh.
#   curl -s dots.riverxia.sh | bash                      pick components interactively
#   curl -s dots.riverxia.sh | bash -s -- --all          everything, no questions after the confirm
#   curl -s dots.riverxia.sh | bash -s -- --only nvim,ghostty
#   flags: -l/--list  -n/--dry-run (change nothing)  -y/--yes (skip the confirm)  -a/--all  --only a,b  -h/--help
# what it does: shallow-clones each component repo into $DOTS_DIR, then symlinks it into ~/.config/<name>.
# anything already at the target is MOVED (never deleted) into ~/.config/.riverxia-dots-backup/<timestamp>/. no sudo, no package installs.
C_NAME=(hypr quickshell nvim fish fastfetch ghostty mpv yazi rofi swaync matugen)
C_REPO=(TogiFerretFerret/hypr TogiFerretFerret/quickshell TogiFerretFerret/nvim-dots TogiFerretFerret/fish-config TogiFerretFerret/fastfetch TogiFerretFerret/ghostty TogiFerretFerret/mpv TogiFerretFerret/yazi TogiFerretFerret/rofi TogiFerretFerret/swaync TogiFerretFerret/matugen)
C_DESC=('hyprland lua config (EVA-00 // ASAHI): modules, binds, animations, a CIELAB k-means color pipeline, QML lockscreen' 'the bar, wallpaper picker, mpris + karaoke lyrics, notification daemon, weather dashboard (Material You via matugen)' 'neovim, from the ground up. lazy.nvim, custom dashboard' 'fish shell: tide prompt, abbreviations, zoxide, helper functions' 'the NERV / MAGI fastfetch layouts, wide and narrow, with colorsync' 'terminal config plus GLSL shaders' 'mpv config, scripts and fonts' 'yazi file manager keymap and theme' 'launcher, clipboard and wallpaper menus' 'notification center theme and toggles' 'color templates that retheme everything from the wallpaper')
C_NOTE=('built for apple silicon / asahi; needs a hyprland with lua config support' 'needs quickshell and matugen; wallpaper picker: touch /tmp/qs-wallpaper-picker' 'avante.nvim needs `make BUILD_FROM_SOURCE=true` in its lazy dir' 'some functions assume my machine (playerctl, zenity, ...)' 'wants a terminal that can show images (ghostty)' '' '' '' '' '' 'templates write into the other configs, install it alongside them')

DOTS_DIR="${DOTS_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/riverxia-dots}"
CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}"
STAMP="$(date +%Y%m%d-%H%M%S)"
BACKUP="$CONFIG/.riverxia-dots-backup/$STAMP"
dry=0 yes=0 all=0 only="" list=0
B=$'\e[1m' G=$'\e[92m' Y=$'\e[93m' P=$'\e[95m' D=$'\e[38;5;110m' R=$'\e[0m'
[ -t 1 ] || B="" G="" Y="" P="" D="" R=""

while [ $# -gt 0 ]; do
  case $1 in
    -n|--dry-run) dry=1 ;; -y|--yes) yes=1 ;; -a|--all) all=1 ;; -l|--list) list=1 ;;
    --only) shift; only=${1:-} ;; --only=*) only=${1#--only=} ;;
    -h|--help) sed -n '2,8p' "$0" 2>/dev/null | sed 's/^# \{0,1\}//' || true; exit 0 ;;
    *) echo "unknown flag: $1 (try --help)" >&2; exit 2 ;;
  esac
  shift
done

say() { printf '%s\n' "$*"; }
ask() { # prompt -> answer (reads the terminal, since stdin is the script when piped)
  local a; { read -r -p "$1" a </dev/tty; } 2>/dev/null || { echo "no terminal to ask on; use --all or --only (and --yes)" >&2; exit 1; }
  printf '%s' "$a"
}

show_list() {
  say "${B}${P}river's dots${R}  ${D}(hyprland on apple silicon / asahi, built from scratch)${R}"
  say ""
  for i in "${!C_NAME[@]}"; do printf ' %s%2d%s  %s%-10s%s %s\n      %s%s%s\n' "$Y" $((i + 1)) "$R" "$B" "${C_NAME[$i]}" "$R" "${C_DESC[$i]}" "$D" "${C_NOTE[$i]}" "$R"; done
  say ""
  say "${D}not installed by this script: sddm (NERV theme, needs root): https://github.com/TogiFerretFerret/nerv-sddm${R}"
}
[ $list = 1 ] && { show_list; exit 0; }

command -v git >/dev/null 2>&1 || { echo "git is required" >&2; exit 1; }

sel=()
if [ -n "$only" ]; then
  IFS=, read -ra want <<<"$only"
  for w in "${want[@]}"; do
    found=-1; for i in "${!C_NAME[@]}"; do [ "${C_NAME[$i]}" = "$w" ] && found=$i; done
    [ $found -ge 0 ] || { echo "unknown component: $w (see --list)" >&2; exit 2; }
    sel+=("$found")
  done
elif [ $all = 1 ]; then
  for i in "${!C_NAME[@]}"; do sel+=("$i"); done
else
  show_list
  ans="$(ask "install which? numbers separated by spaces, 'a' for all, q to quit: ")"
  case $ans in q|Q|"") echo "nothing installed."; exit 0 ;; a|A) for i in "${!C_NAME[@]}"; do sel+=("$i"); done ;;
    *) for n in $ans; do [[ $n =~ ^[0-9]+$ ]] && [ "$n" -ge 1 ] && [ "$n" -le "${#C_NAME[@]}" ] && sel+=("$((n - 1))") || { echo "bad choice: $n" >&2; exit 2; }; done ;;
  esac
fi
[ ${#sel[@]} -gt 0 ] || { echo "nothing selected."; exit 0; }

say ""
say "${B}plan${R} ${D}(dots dir: $DOTS_DIR)${R}"
for i in "${sel[@]}"; do printf '  %s%-10s%s %s -> %s\n' "$G" "${C_NAME[$i]}" "$R" "$DOTS_DIR/${C_NAME[$i]}" "$CONFIG/${C_NAME[$i]}"; done
say "  ${D}existing configs at those paths are moved to $BACKUP${R}"
say "  ${D}these were written for one machine; read each repo before trusting it on yours${R}"
if [ $dry = 1 ]; then say ""; say "dry run: nothing changed."; exit 0; fi
if [ $yes != 1 ]; then
  [ "$(ask "go? [y/N] ")" = y ] || { echo "cancelled, nothing changed."; exit 0; }
fi

mkdir -p "$DOTS_DIR" "$CONFIG"
for i in "${sel[@]}"; do
  name=${C_NAME[$i]} repo=${C_REPO[$i]} src="$DOTS_DIR/$name" dst="$CONFIG/$name"
  say ""; say "${B}$name${R}"
  if [ -d "$src/.git" ]; then
    git -C "$src" pull --ff-only -q && say "  updated $src" || say "  ${Y}could not fast-forward $src (local changes?), leaving it as is${R}"
  else
    git clone --depth 1 -q "https://github.com/$repo" "$src" || { say "  ${Y}clone failed, skipping${R}"; continue; }
    say "  cloned $repo"
  fi
  if [ -L "$dst" ] && [ "$(readlink "$dst")" = "$src" ]; then say "  already linked"; continue; fi
  if [ -e "$dst" ] || [ -L "$dst" ]; then
    mkdir -p "$BACKUP"; mv "$dst" "$BACKUP/$name"; say "  moved old $dst to $BACKUP/$name"
  fi
  ln -s "$src" "$dst" && say "  linked $dst"
  [ -n "${C_NOTE[$i]}" ] && say "  ${D}note: ${C_NOTE[$i]}${R}"
done
say ""
say "${G}done.${R} edit files in $DOTS_DIR/<name> (they are real git clones). to undo one: rm the symlink and move its folder back from $BACKUP"
