#!/usr/bin/env bash
#
# upgrade.sh — bring an existing (bare-metal) MAESTRO checkout safely up to the
# latest version after a `git pull`.
#
# Why this exists
# ---------------
# `scripts/server.sh restart` rebuilds the server (dist/) but NOT the UI:
# `ui/dist` is gitignored and built separately, and npm deps are never
# refreshed. So after a `git pull` that touched dependencies or the frontend, a
# plain restart can leave a stale/missing UI bundle or ABI-mismatched native
# modules. This script runs the full, correct update sequence instead:
#
#     git pull (optional)  ->  build-all.sh (deps + server + UI)  ->  restart
#
# Network bind migration (2026-06-10)
# -----------------------------------
# A security fix changed the default bind from 0.0.0.0 to 127.0.0.1 (loopback
# only). If you used to reach MAESTRO from another machine on a bare-metal
# install, after upgrading you'll get ERR_CONNECTION_REFUSED until you set HOST
# explicitly. This script detects that and offers to write HOST to .env (with a
# warning that you must enable auth before exposing a non-loopback interface).
#
# Usage:
#   scripts/upgrade.sh                 # interactive: pull, build, restart
#   scripts/upgrade.sh --no-pull       # skip `git pull` (build + restart only)
#   scripts/upgrade.sh --no-restart    # build only, leave the server as-is
#   scripts/upgrade.sh --yes           # non-interactive (CI); never edits .env
#   scripts/upgrade.sh --help
#
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
ENV_FILE="$PROJECT_DIR/.env"

DO_PULL=1
DO_RESTART=1
ASSUME_YES=0

for arg in "$@"; do
  case "$arg" in
    --no-pull)    DO_PULL=0 ;;
    --no-restart) DO_RESTART=0 ;;
    --yes|-y)     ASSUME_YES=1 ;;
    -h|--help)
      sed -n '2,29p' "$0" | sed 's/^# \{0,1\}//'
      exit 0
      ;;
    *)
      echo "upgrade.sh: unknown option '$arg' (try --help)" >&2
      exit 2
      ;;
  esac
done

cd "$PROJECT_DIR"

say() { printf '\n\033[1;36m==>\033[0m %s\n' "$1"; }
warn() { printf '\033[1;33mWARN:\033[0m %s\n' "$1" >&2; }

# ---------------------------------------------------------------------------
# 1. git pull (fast-forward only; never silently merge or rewrite local work)
# ---------------------------------------------------------------------------
if [[ "$DO_PULL" -eq 1 ]]; then
  if [[ -n "$(git -C "$PROJECT_DIR" status --porcelain 2>/dev/null)" ]]; then
    warn "working tree has local changes — skipping 'git pull'. Commit/stash and re-run, or use --no-pull."
  else
    say "Pulling latest changes (git pull --ff-only)"
    if ! git -C "$PROJECT_DIR" pull --ff-only; then
      warn "git pull --ff-only failed (diverged or offline). Continuing with the current checkout."
    fi
  fi
else
  say "Skipping git pull (--no-pull)"
fi

# ---------------------------------------------------------------------------
# 2. Full rebuild: refresh deps + build server dist/ AND ui/dist/ + prebake.
#    This is the step a plain `server.sh restart` skips for the UI.
# ---------------------------------------------------------------------------
say "Rebuilding (deps + server + UI) via scripts/build-all.sh"
"$SCRIPT_DIR/build-all.sh"

# ---------------------------------------------------------------------------
# 3. Network bind migration check (0.0.0.0 -> 127.0.0.1 default since 2026-06-10)
# ---------------------------------------------------------------------------
host_in_env=""
if [[ -f "$ENV_FILE" ]]; then
  # First non-comment HOST=... line, value with surrounding quotes stripped.
  host_in_env="$(grep -E '^[[:space:]]*(export[[:space:]]+)?HOST=' "$ENV_FILE" \
    | grep -vE '^[[:space:]]*#' \
    | head -1 | sed -E 's/^[[:space:]]*(export[[:space:]]+)?HOST=//; s/^["'\'']//; s/["'\'']$//')"
fi

say "Checking network bind"
if [[ -n "${HOST:-}" ]]; then
  echo "    HOST is set in the environment ($HOST) — bind is explicit, nothing to migrate."
elif [[ -n "$host_in_env" ]]; then
  echo "    HOST=$host_in_env found in .env — bind is explicit, nothing to migrate."
else
  cat <<'EOF'
    HOST is not set, so the server now binds 127.0.0.1 (loopback only).
    Since 2026-06-10 the default changed from 0.0.0.0 for security: the agent
    API includes a Bash tool, so an auth-less instance on the LAN is effectively
    unauthenticated remote code execution.

    If you ONLY open MAESTRO from this same machine (http://localhost:9876),
    no action is needed.

    If you reach it from ANOTHER machine, that is why you now get
    ERR_CONNECTION_REFUSED. To restore remote access you must set HOST
    explicitly -- and you should enable auth (auth.local or OAuth) in
    config.yaml before exposing a non-loopback interface.
EOF
  if [[ "$ASSUME_YES" -eq 0 ]]; then
    printf '\n    Append HOST=0.0.0.0 to .env now? Only do this if auth is (or will be) enabled. [y/N] '
    read -r reply || reply=""
    if [[ "$reply" =~ ^[Yy]$ ]]; then
      { [[ -f "$ENV_FILE" && -n "$(tail -c1 "$ENV_FILE" 2>/dev/null)" ]] && echo "" >> "$ENV_FILE"; } || true
      printf '\n# Added by scripts/upgrade.sh: restore non-loopback bind (enable auth first!)\nHOST=0.0.0.0\n' >> "$ENV_FILE"
      echo "    Wrote HOST=0.0.0.0 to $ENV_FILE"
    else
      echo "    Left .env unchanged. Set HOST=0.0.0.0 in .env manually when ready."
    fi
  else
    warn "non-interactive (--yes): not editing .env. Set HOST in .env manually if you need remote access."
  fi
fi

# ---------------------------------------------------------------------------
# 4. Restart
# ---------------------------------------------------------------------------
if [[ "$DO_RESTART" -eq 1 ]]; then
  say "Restarting server (scripts/server.sh restart)"
  "$SCRIPT_DIR/server.sh" restart
  echo
  echo "Done. If the server is healthy, open it at the bind address reported above"
  echo "(loopback default: http://localhost:9876)."
else
  say "Build complete (--no-restart). Start the server with: scripts/server.sh restart"
fi
