#!/usr/bin/env bash
# stop-metro.sh — stop the Metro dev server this checkout owns and close its
# log-tail window. Port-scoped like start-metro: only the listener on the
# resolved port is signalled, so concurrent slots on other ports are untouched.
# Idempotent: nothing running is a success, not an error.
set -euo pipefail

TARGET="."
PORT="${WATCHER_PORT:-}"
while [ $# -gt 0 ]; do
  case "$1" in
    --target) TARGET="$2"; shift 2 ;;
    --port)   PORT="$2"; shift 2 ;;
    -h|--help)
      printf 'Usage: stop-metro.sh [--target <dir>] [--port <port>]\n'
      printf '  --target  MetaMask Mobile checkout directory\n'
      printf '  --port    Metro port (default: WATCHER_PORT env, else the slot context, else 8081)\n'
      exit 0
      ;;
    *) printf 'stop-metro: unknown arg: %s\n' "$1" >&2; exit 2 ;;
  esac
done

TARGET="$(cd "$TARGET" && pwd -P)"

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck disable=SC1091
. "$SCRIPT_DIR/../shared/harness-path.sh"
if ! command -v recipe_runtime_dir >/dev/null 2>&1; then
  echo "stop-metro: shared lib adapters/shared/harness-path.sh not found; reinstall the runner." >&2
  exit 1
fi

# No explicit port: resolve the checkout's own (slot context first, then the
# pool/formula fallbacks) so we stop THIS slot's Metro, not the 8081 default.
if [ -z "$PORT" ]; then
  # shellcheck disable=SC1091
  . "$SCRIPT_DIR/../shared/resolve-slot-ports.sh"
  resolved_port="$(resolve_mobile_runtime_ports "$TARGET" 2>/dev/null | sed -n 's/^WATCHER_PORT=//p' | head -1 || true)"
  PORT="${resolved_port:-8081}"
fi

LOG_DIR="$TARGET/$(recipe_runtime_dir)"
PID_FILE="$LOG_DIR/metro.pid"
TMUX_FILE="$LOG_DIR/metro.tmux"

# shellcheck disable=SC1091
. "$SCRIPT_DIR/lib/metro-listener.sh"

pids="$(metro_listener_pids 2>/dev/null || true)"
if [ -n "$pids" ]; then
  stop_metro_listener || exit 1
  printf 'Stopped Metro on port %s (pid %s)\n' "$PORT" "$pids" >&2
else
  printf 'Metro not running on port %s — nothing to stop\n' "$PORT" >&2
fi

# The stop decision is made; everything below is best-effort cleanup (pid file,
# leaked-bundler sweep, tmux window). None of it may fail the command — the
# idempotent-stop contract is already satisfied. Drop set -e for the tail so an
# incidental non-zero (platform-dependent) can never turn success into exit 1.
set +e
rm -f "$PID_FILE"
rm -f "$LOG_DIR/metro-launch.json"
rm -f "$LOG_DIR/metro-build-env.sh"

# start-metro runs a per-checkout console-forwarder holding the device debugger
# slot; Metro going down must take it too, or the orphan keeps polling and later
# fights a fresh forwarder over the slot. Kill the pid this LOG_DIR recorded,
# then sweep forwarders started under a different RECIPE_RUNTIME_DIR of this
# same checkout (their pid files live elsewhere; match on the --out path).
FWD_PID_FILE="$LOG_DIR/console-forwarder.pid"
fwd_pid="$(cat "$FWD_PID_FILE" 2>/dev/null || true)"
# A crash can leave a stale pid file and the OS can recycle the pid for an
# unrelated process — only kill when the command line is really ours.
if [ -n "$fwd_pid" ]; then
  case "$(ps -p "$fwd_pid" -o command= 2>/dev/null)" in
    *console-forwarder.cjs*)
      if kill "$fwd_pid" 2>/dev/null; then
        printf 'Stopped console forwarder (pid %s)\n' "$fwd_pid" >&2
      fi
      ;;
  esac
fi
rm -f "$FWD_PID_FILE"
pkill -f "console-forwarder.cjs --port $PORT --out $TARGET/" 2>/dev/null

# Reap a detached bundler for this exact port when its listener disappeared
# before the normal stop path. Other ports in the same checkout are separate
# runtime generations and must remain untouched.
if [ -f "$SCRIPT_DIR/../shared/reap-checkout-metros.sh" ]; then
  . "$SCRIPT_DIR/../shared/reap-checkout-metros.sh"
  reap_checkout_metros_on_port "$TARGET" "$PORT" || true
fi

# Close the read-only log-tail window start-metro opened, if it is still there.
if [ -f "$TMUX_FILE" ] && command -v tmux >/dev/null 2>&1; then
  win="$(cat "$TMUX_FILE" 2>/dev/null || true)"
  if [ -n "$win" ] && tmux kill-window -t "$win" 2>/dev/null; then
    printf 'Closed Metro log window %s\n' "$win" >&2
  fi
fi
rm -f "$TMUX_FILE"

# A stopped checkout must not remain in Watchman's global root set. Metro will
# add the root again on the next launch; removing only this exact target keeps
# every other active slot untouched.
if command -v watchman >/dev/null 2>&1; then
  if watchman watch-del "$TARGET" >/dev/null 2>&1; then
    printf 'Removed Watchman root %s\n' "$TARGET" >&2
  fi
fi

# Reaching here = cleanup done (nothing needed stopping, or it stopped and
# windows/pids were cleared). The idempotent-stop contract is success; do not
# leak an incidental non-zero from the last command on any platform.
exit 0
