#!/bin/bash
# run.sh — launch the real Nightshift M1-M4.app binary against a copy of
# its web root with bench.js injected, wait for the harness to finish,
# and capture everything.
#
#   bash run.sh <label> <config.json> [simulate_mem_gb] [timeout_min]
#
# Raw output: ../raw/<label>.log (app stderr: every "page: {bench…}"
# line) and ../raw/<label>-sys.tsv (system memory samples every 5 s).
set -u
HERE="$(cd "$(dirname "$0")" && pwd)"
RAW="$HERE/../raw"
LABEL="$1"; CONFIG="$2"; SIM="${3:-}"; TIMEOUT_MIN="${4:-240}"
BUILD="$HOME/nightshift-m1m4-build"
SRC_WEB="$BUILD/web-mac"
WEB="$BUILD/web-bench"
APP="$BUILD/dist-mac-m1m4/Nightshift M1-M4.app"
BIN="$APP/Contents/MacOS/nightshift-m1m4"
mkdir -p "$RAW"

[ -x "$BIN" ] || { echo "no app binary at $BIN" >&2; exit 1; }
pgrep -x nightshift-m1m4 >/dev/null && { echo "an instance is already running — refusing" >&2; exit 1; }

# The bench root = the app's own web root (the bundled copy, so we test
# what ships) + bench.js after mac-layer.js + the run's config.
rsync -a --delete --exclude '._*' --exclude '.DS_Store' "$APP/Contents/Resources/web/" "$WEB/"
cp "$HERE/bench.js" "$WEB/js/mac/bench.js"
cp "$CONFIG" "$WEB/bench-config.json"
python3 - "$WEB/index.html" <<'PY'
import sys
p = sys.argv[1]
s = open(p, encoding='utf-8').read()
tag = '<script defer src="js/mac/mac-layer.js"></script>'
add = tag + '\n  <script defer src="js/mac/bench.js"></script>'
assert s.count(tag) == 1, 'mac-layer tag not found exactly once'
if 'js/mac/bench.js' not in s:
    s = s.replace(tag, add)
open(p, 'w', encoding='utf-8').write(s)
PY

LOG="$RAW/$LABEL.log"; SYS="$RAW/$LABEL-sys.tsv"
: > "$LOG"
echo -e "epoch\tpressure_level\tfree_pct\tswap_used_mb\tpages_free\tpages_active\tpages_wired\tpages_compressed\twebkit_rss_mb\tapp_rss_mb" > "$SYS"
echo "[run] $LABEL · config $(basename "$CONFIG") · sim=${SIM:-none} · timeout ${TIMEOUT_MIN}m"
# extra env for the app (e.g. NS_MAC_TEST_PARK_AFTER_S=20) via $APP_ENV
if [ -n "$SIM" ]; then
  env ${APP_ENV:-} NS_MAC_WEB_ROOT="$WEB" NS_MAC_SIMULATE_MEM_GB="$SIM" "$BIN" >>"$LOG" 2>&1 &
else
  env ${APP_ENV:-} NS_MAC_WEB_ROOT="$WEB" "$BIN" >>"$LOG" 2>&1 &
fi
PID=$!
START=$(date +%s)
# WebContent footprint at 1 s (load spikes last ~3 s; the 5 s loop misses them)
FP="$RAW/$LABEL-footprint.tsv"
echo -e "epoch\twebcontent_pid\twebcontent_mb\tgpu_mb" > "$FP"
(
  while kill -0 $PID 2>/dev/null; do
    wc=$(pgrep -P $PID -f com.apple.WebKit.WebContent | tail -1); [ -z "$wc" ] && wc=$(pgrep -f com.apple.WebKit.WebContent | tail -1)
    gp=$(pgrep -f com.apple.WebKit.GPU | tail -1)
    top -l 1 -stats pid,mem -pid ${wc:-0} -pid ${gp:-0} 2>/dev/null | awk -v t=$(date +%s) -v wc="$wc" -v gp="$gp" '
      function mb(v){ u=substr(v,length(v)); n=v+0; if(u=="G") return n*1024; if(u=="K") return n/1024; return n }
      $1==wc {w=mb($2)} $1==gp {g=mb($2)} END {printf "%s\t%s\t%d\t%d\n", t, wc, w, g}' >> "$FP"
    sleep ${FP_SLEEP:-1}
  done
) &
# optional: WebContent phys_footprint every $FPS_MS ms (harness/fpsample.swift,
# built to ~/nightshift-m1m4-build/fpsample) — WebKit's kill check reads this
if [ -n "${FPS_MS:-}" ] && [ -x "$BUILD/fpsample" ]; then
  "$BUILD/fpsample" "$FPS_MS" $PID > "$RAW/$LABEL-fps.tsv" 2>/dev/null &
fi
# optional: WebContent RSS every $RSS_SLEEP s (ps is ~5 ms; load garbage is CPU memory)
if [ -n "${RSS_SLEEP:-}" ]; then
  RS="$RAW/$LABEL-rss.tsv"; echo -e "t_ms\twebcontent_pid\trss_mb" > "$RS"
  ( while kill -0 $PID 2>/dev/null; do
      wc=$(pgrep -f com.apple.WebKit.WebContent | tail -1)
      [ -n "$wc" ] && echo -e "$(python3 -c 'import time;print(int(time.time()*1000))')\t$wc\t$(( $(ps -o rss= -p $wc 2>/dev/null || echo 0) / 1024 ))" >> "$RS"
      sleep "$RSS_SLEEP"
    done ) &
fi
status="timeout"
while :; do
  sleep 5
  now=$(date +%s)
  vm=$(vm_stat)
  pg() { echo "$vm" | awk -v k="$1" -F: '$1==k {gsub(/[ .]/,"",$2); print $2}'; }
  swap=$(sysctl -n vm.swapusage | awk '{for(i=1;i<=NF;i++) if($i=="used") {v=$(i+2); sub(/M/,"",v); print v}}')
  wk=$(ps -axo rss=,comm= | awk '/WebKit|com.apple.WebKit/ {s+=$1} END {printf "%d", s/1024}')
  app=$(ps -o rss= -p $PID 2>/dev/null | awk '{printf "%d", $1/1024}')
  echo -e "$now\t$(sysctl -n kern.memorystatus_vm_pressure_level)\t$(sysctl -n kern.memorystatus_level)\t$swap\t$(pg 'Pages free')\t$(pg 'Pages active')\t$(pg 'Pages wired down')\t$(pg 'Pages occupied by compressor')\t$wk\t${app:-0}" >> "$SYS"
  if grep -q '"type":"done"' "$LOG"; then status="done"; break; fi
  if ! kill -0 $PID 2>/dev/null; then status="exited"; break; fi
  if [ $((now - START)) -gt $((TIMEOUT_MIN * 60)) ]; then status="timeout"; break; fi
done
echo "[run] $LABEL finished: $status after $(( $(date +%s) - START ))s"
kill $PID 2>/dev/null; sleep 3; kill -9 $PID 2>/dev/null
# WebKit helper processes are owned by the app and exit with it.
exit 0
