#!/usr/bin/env bash
# bootstrap — install everything amux needs on THIS machine, whatever it is.
#
# Detects the platform and its package manager, then installs what is missing:
#   tmux         the multiplexer every session runs inside
#   python3      amux's server is a Python program
#   curl         used to talk to every amux server
#   amux         the session manager itself (upstream: github.com/mixpeek/amux)
#   claude       the agent amux drives (optional: --no-claude to skip)
#
# It asks before installing anything, prints the exact command it will run, and
# skips whatever is already present. Safe to re-run — nothing here is destructive.
#
# Usage:
#   setup/bootstrap                 interactive
#   setup/bootstrap --yes           assume yes (for scripted setup)
#   setup/bootstrap --no-claude     skip installing Claude Code
#   setup/bootstrap --dry-run       print what it WOULD do, change nothing
#
# On Windows this is where the tiers get decided; see docs/windows.md.
# Afterwards, run `amux-doctor` — it verifies what this actually accomplished.
set -uo pipefail

_here=$(cd "$(dirname "$0")" && pwd)
. "$_here/../lib/amux-common.sh"

case "${1:-}" in -h|--help) amux_self_help "$0"; exit 0 ;; esac

ASSUME_YES=0 WANT_CLAUDE=1 DRY=0
while [ $# -gt 0 ]; do
  case "$1" in
    -y|--yes)     ASSUME_YES=1 ;;
    --no-claude)  WANT_CLAUDE=0 ;;
    --dry-run)    DRY=1 ;;
    *)            amux_die "unknown option: $1 (see -h)" ;;
  esac
  shift
done

PLATFORM=$(amux_platform)
PKGMGR=$(amux_pkgmgr)

printf '%samux-nuilab bootstrap%s\n' "$BOLD" "$RESET"
printf '  platform     %s\n' "$(amux_platform_label)"
printf '  package mgr  %s\n' "$PKGMGR"
printf '  downloader   %s\n' "$(amux_downloader)"
printf '\n'

if [ "$PKGMGR" = none ]; then
  amux_warn "no package manager found — this script can still tell you what to install,"
  amux_warn "but you will have to run the installs yourself."
  case "$PLATFORM" in
    macos) printf '  Get Homebrew:  https://brew.sh\n' ;;
    msys)  printf '  Get MSYS2 (gives you pacman AND a real tmux):  https://www.msys2.org\n'
           printf '  Or Scoop (no admin rights needed):            https://scoop.sh\n' ;;
  esac
  printf '\n'
fi

# ask <prompt> — honors --yes and --dry-run.
#
# Under --dry-run this must still ANNOUNCE the question before declining it.
# Returning silently made `--dry-run` print an empty "amux" section on a machine
# with no amux — hiding the single most important thing it was about to do, which
# is the opposite of what a dry run is for.
ask() {
  if [ "$DRY" = 1 ]; then
    printf '    %s[dry-run]%s would ask: %s\n' "$DIM" "$RESET" "$1"
    return 1
  fi
  [ "$ASSUME_YES" = 1 ] && return 0
  if [ ! -t 0 ]; then
    # Non-interactive and no --yes: do not guess, but say what was skipped.
    printf '    %sskipped (not interactive; use --yes):%s %s\n' "$DIM" "$RESET" "$1"
    return 1
  fi
  printf '%s [Y/n] ' "$1"
  local a; read -r a
  case "$a" in n|N|no|NO) return 1 ;; *) return 0 ;; esac
}

run() { # echo then run, unless --dry-run
  printf '    %s$ %s%s\n' "$DIM" "$*" "$RESET"
  [ "$DRY" = 1 ] && return 0
  "$@"
}

need_install() { # $1 = command, $2 = package name
  if amux_have "$1"; then
    amux_ok "$1 already installed"
    return 1
  fi
  return 0
}

# ── tmux ─────────────────────────────────────────────────────────────────────
# The one dependency that genuinely may not be satisfiable, on Windows outside
# WSL. Be honest about that rather than failing three steps later.
printf '%sSession multiplexer%s\n' "$BOLD" "$RESET"
if need_install tmux tmux; then
  case "$PLATFORM" in
    msys|cygwin)
      if [ "$PKGMGR" = msys2 ]; then
        amux_info "MSYS2 detected — it ships a real tmux."
        ask "  Install tmux with pacman?" && run pacman -S --noconfirm tmux
      else
        amux_hmm "no tmux, and no MSYS2 pacman to install one."
        printf '      Without tmux this machine cannot RUN sessions locally.\n'
        printf '      It CAN still drive other machines (amux-remote, amux-all, ccjump).\n'
        printf '      To run sessions here, install MSYS2 (https://www.msys2.org)\n'
        printf '      and then:  pacman -S tmux\n'
      fi ;;
    *)
      ask "  Install tmux ($(amux_pkg_install_cmd tmux))?" && amux_pkg_install tmux
      ;;
  esac
fi

# ── python3 + curl ───────────────────────────────────────────────────────────
printf '\n%sCore tools%s\n' "$BOLD" "$RESET"
if need_install python3 python3; then
  ask "  Install python3 ($(amux_pkg_install_cmd python3))?" && amux_pkg_install python3
fi
if ! amux_have curl && ! amux_have wget; then
  ask "  Install curl ($(amux_pkg_install_cmd curl))?" && amux_pkg_install curl
else
  amux_ok "have a downloader ($(amux_downloader))"
fi

# ── amux ─────────────────────────────────────────────────────────────────────
# amux is NOT on PyPI — `pip install amux` fails with "from versions: none", and
# there is no pipx or uv route either. It ships two ways only:
#   * a Homebrew tap, macOS only
#   * git clone + its own install.sh, which simply copies three files
# install.sh defaults to /usr/local/bin (needs sudo); AMUX_INSTALL_DIR redirects
# it to ~/.local/bin so a student with no sudo on a lab machine can still install.
AMUX_REPO="https://github.com/mixpeek/amux"
printf '\n%samux%s  %s(github.com/mixpeek/amux — MIT + Commons Clause)%s\n' \
  "$BOLD" "$RESET" "$DIM" "$RESET"

install_amux_from_source() {
  local dest="$HOME/.local/bin" src
  amux_have git || { amux_warn "git is required to install amux from source"; return 1; }
  src=$(mktemp -d "${TMPDIR:-/tmp}/amux-src.XXXXXX") || return 1
  printf '    %s$ git clone --depth 1 %s%s\n' "$DIM" "$AMUX_REPO" "$RESET"
  if [ "$DRY" = 1 ]; then rm -rf "$src"; return 0; fi
  git clone --depth 1 -q "$AMUX_REPO" "$src/amux" || { rm -rf "$src"; return 1; }
  mkdir -p "$dest"
  # Use upstream's own installer, redirected to a per-user prefix, so we inherit
  # whatever files it decides to ship rather than hardcoding a list here.
  ( cd "$src/amux" && AMUX_INSTALL_DIR="$dest" bash ./install.sh ) >/dev/null 2>&1
  local rc=$?
  rm -rf "$src"
  [ "$rc" = 0 ] && [ -x "$dest/amux" ]
}

if need_install amux amux; then
  installed=0
  if [ "$PKGMGR" = brew ]; then
    if ask "  Install amux with Homebrew (mixpeek tap)?"; then
      run brew install mixpeek/amux/amux && installed=1
    fi
  fi
  if [ "$installed" = 0 ]; then
    if ask "  Install amux from source into ~/.local/bin (no sudo)?"; then
      if install_amux_from_source; then
        installed=1
        amux_ok "amux installed to $HOME/.local/bin"
      else
        amux_bad "installing amux from source failed"
      fi
    fi
  fi

  # Upstream ships its OWN amux-remote under the same name we use, so installing
  # amux after ./install.sh silently replaces our symlink with upstream's copy —
  # losing the compact grid and the fix that keeps the token off curl's argv.
  # Re-assert our links so the result does not depend on which order you ran
  # bootstrap and install.sh in. install.sh is idempotent, so this is free.
  if [ "$installed" = 1 ] && [ "$DRY" = 0 ] && [ -x "$_here/../install.sh" ]; then
    run "$_here/../install.sh"
    amux_info "re-linked amux-nuilab commands (upstream ships its own amux-remote)"
  fi
  if [ "$installed" = 0 ]; then
    amux_hmm "amux was not installed. Do it manually with:"
    printf '      git clone %s\n' "$AMUX_REPO"
    printf '      cd amux && AMUX_INSTALL_DIR="$HOME/.local/bin" ./install.sh\n'
    [ "$PKGMGR" = brew ] && printf '      (or: brew install mixpeek/amux/amux)\n'
    AMUX_MISSING=1
  fi
fi

# ── Claude Code ──────────────────────────────────────────────────────────────
if [ "$WANT_CLAUDE" = 1 ]; then
  printf '\n%sClaude Code%s\n' "$BOLD" "$RESET"
  if need_install claude claude; then
    case "$PLATFORM" in
      macos|linux|wsl)
        if ask "  Install Claude Code (curl https://claude.ai/install.sh | bash)?"; then
          [ "$DRY" = 1 ] || curl -fsSL https://claude.ai/install.sh | bash
        fi ;;
      msys|cygwin)
        amux_info "On Windows, install Claude Code natively from PowerShell:"
        printf '      irm https://claude.ai/install.ps1 | iex\n'
        printf '      (or: winget install Anthropic.ClaudeCode)\n'
        printf '      Then it is on your PATH here in Git Bash too.\n' ;;
    esac
  fi
  printf '\n  %sAfter installing, choose how it authenticates — this decides whether%s\n' "$DIM" "$RESET"
  printf '  %sbrowser control works. See docs/auth.md.%s\n' "$DIM" "$RESET"
fi

# ── done ─────────────────────────────────────────────────────────────────────
# Report honestly. Saying "Bootstrap complete" after amux failed to install sends
# the student to the next step with the one indispensable piece missing.
printf '\n%s' "$BOLD"
if [ "$DRY" = 1 ]; then
  printf 'Dry run complete — nothing was changed.\n'
elif [ "${AMUX_MISSING:-0}" = 1 ]; then
  printf '%sBootstrap finished, but amux is still missing.%s\n' "$RED" "$RESET"
else
  printf 'Bootstrap complete.\n'
fi
printf '%s' "$RESET"
cat <<EOF

Next steps:
  1. amux-doctor                     verify what this machine can actually do
  2. setup/serve-install             let OTHER machines reach this one (optional)
  3. amux-config add <name> --host <address>
                                     add a machine you want to drive from here
EOF

# Non-zero when the essential piece is absent, so a scripted setup can tell.
[ "${AMUX_MISSING:-0}" = 1 ] && exit 1
exit 0
