#!/usr/bin/env bash
# Build huskies, install (codesign-heal wrapper + underlying binary), and if a
# gateway is running on this host, hot-restart it detached from the current shell
# so SSH disconnect — e.g. when redeploying from a phone — doesn't kill it.
#
# Skips the restart silently if no gateway is running. Errors loudly if more
# than one matches, so we don't restart the wrong one.
#
# Pass --skip-check to bypass `script/check` (useful for docs / build-script
# changes you've already verified).
#
# On relaunch failure the previous binary is restored from
# ~/bin/huskies-bin.prev and re-launched, so a bad deploy doesn't leave the
# host without a working gateway.
#
# After a `cp` or download the binary loses its ad-hoc signature and macOS
# SIGKILLs it silently on Apple Silicon. The wrapper at ~/bin/huskies re-signs
# the underlying binary at ~/bin/huskies-bin whenever codesign validation
# fails, then execs it. Normal launches (already signed) are zero-overhead.
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
LOG_DIR="${HUSKIES_LOG_DIR:-$PROJECT_ROOT/logs}"
GATEWAY_PATTERN='huskies .*--gateway'
BIN_DIR="${HOME}/bin"
UNDERLYING="${BIN_DIR}/huskies-bin"
WRAPPER="${BIN_DIR}/huskies"
PREV_BIN="${BIN_DIR}/huskies-bin.prev"
NEW_BIN="${PROJECT_ROOT}/target/release/huskies"

SKIP_CHECK=0
for arg in "$@"; do
  case "$arg" in
    --skip-check) SKIP_CHECK=1 ;;
    -h|--help) sed -n '2,17p' "$0"; exit 0 ;;
    *) echo "Unknown arg: $arg (use --help)" >&2; exit 2 ;;
  esac
done

if [ "$SKIP_CHECK" -eq 0 ] && [ -x "$SCRIPT_DIR/check" ]; then
  echo "=== Running script/check ==="
  "$SCRIPT_DIR/check"
fi

echo "=== Building release binary ==="
cd "$PROJECT_ROOT"
cargo build --release --bin huskies

mkdir -p "$BIN_DIR"

# Snapshot current binary so we can roll back if the relaunch fails.
PREV_VERSION=""
if [ -x "$UNDERLYING" ]; then
  PREV_VERSION="$("$UNDERLYING" --version 2>/dev/null || echo unknown)"
  cp "$UNDERLYING" "$PREV_BIN"
fi

cp "$NEW_BIN" "$UNDERLYING"
chmod +x "$UNDERLYING"
codesign -s - -f "$UNDERLYING" 2>/dev/null
NEW_VERSION="$("$UNDERLYING" --version 2>/dev/null || echo unknown)"
echo "==> Installed binary:  ${UNDERLYING}"
if [ -n "$PREV_VERSION" ]; then
  echo "    version: $PREV_VERSION  →  $NEW_VERSION"
else
  echo "    version: $NEW_VERSION (no prior install)"
fi

cat > "${WRAPPER}" << 'WRAPPER_EOF'
#!/usr/bin/env bash
# Codesign-heal wrapper — re-signs ~/bin/huskies-bin if the signature is
# missing or invalid, then execs the binary.  Logs only when it re-signs.
BIN="${HOME}/bin/huskies-bin"
if ! codesign --verify --quiet "${BIN}" 2>/dev/null; then
    codesign -s - "${BIN}"
    echo "[codesign-heal] re-signed ~/bin/huskies-bin" >&2
fi
exec "${BIN}" "$@"
WRAPPER_EOF
chmod +x "${WRAPPER}"
echo "==> Installed wrapper: ${WRAPPER}"

# ── Hot-restart gateway if one is running ─────────────────────────────
collect_descendants() {
  local pid="$1" kid
  for kid in $(pgrep -P "$pid" 2>/dev/null); do
    collect_descendants "$kid"
    printf '%s\n' "$kid"
  done
}

GATEWAY_PIDS="$(pgrep -f "$GATEWAY_PATTERN" || true)"
if [ -z "$GATEWAY_PIDS" ]; then
  echo "==> No running gateway found; install complete."
  exit 0
fi

if [ "$(echo "$GATEWAY_PIDS" | wc -l)" -gt 1 ]; then
  echo "Error: multiple gateway processes match '${GATEWAY_PATTERN}':" >&2
  ps -p $GATEWAY_PIDS -o pid,args >&2 || true
  echo "Refusing to guess which to restart." >&2
  exit 3
fi

GATEWAY_PID="$GATEWAY_PIDS"
GATEWAY_ARGS="$(ps -p "$GATEWAY_PID" -o args= | sed -E 's@^[^ ]*huskies[^ ]* @@')"
GATEWAY_CWD="$(lsof -p "$GATEWAY_PID" 2>/dev/null | awk '$4=="cwd"{print $9; exit}')"
if [ -z "$GATEWAY_CWD" ]; then GATEWAY_CWD="$PWD"; fi

LOG_FILE="$LOG_DIR/gateway-$(date +%Y%m%d-%H%M%S).log"
mkdir -p "$LOG_DIR"

DESCENDANTS="$(collect_descendants "$GATEWAY_PID" | tr '\n' ' ')"
echo "==> Stopping gateway tree (pids: $GATEWAY_PID $DESCENDANTS)"
# Kill descendants depth-first so PTY children die before the gateway, then the gateway.
for pid in $DESCENDANTS $GATEWAY_PID; do
  kill "$pid" 2>/dev/null || true
done
sleep 2

echo "==> Restarting gateway"
echo "    log: $LOG_FILE"
(
  cd "$GATEWAY_CWD"
  nohup "$WRAPPER" $GATEWAY_ARGS >> "$LOG_FILE" 2>&1 < /dev/null &
  disown
)

# Wait up to 10s for the new gateway to appear AND be a different PID.
NEW_PID=""
for _ in 1 2 3 4 5 6 7 8 9 10; do
  sleep 1
  candidate="$(pgrep -f "$GATEWAY_PATTERN" 2>/dev/null || true)"
  if [ -n "$candidate" ] && [ "$candidate" != "$GATEWAY_PID" ]; then
    NEW_PID="$candidate"
    break
  fi
done

if [ -n "$NEW_PID" ]; then
  echo "==> Gateway restarted as pid $NEW_PID"
  exit 0
fi

# ── Rollback ──────────────────────────────────────────────────────────
echo "Error: new gateway failed to come up within 10s; rolling back" >&2
if [ -x "$PREV_BIN" ]; then
  cp "$PREV_BIN" "$UNDERLYING"
  chmod +x "$UNDERLYING"
  codesign -s - -f "$UNDERLYING" 2>/dev/null
  echo "==> Restored previous binary"
  (
    cd "$GATEWAY_CWD"
    nohup "$WRAPPER" $GATEWAY_ARGS >> "$LOG_FILE" 2>&1 < /dev/null &
    disown
  )
  sleep 2
  if pgrep -f "$GATEWAY_PATTERN" >/dev/null 2>&1; then
    echo "==> Gateway restored to previous version"
    exit 1
  fi
fi
echo "Error: rollback failed; gateway is DOWN. Inspect $LOG_FILE." >&2
exit 1
