#!/usr/bin/env bash
#
# endpoint_diff/resample.sh <before-ref> <after-ref> [runs]
#
# Follow-up to a compare.py run that found COMMIT-attributed differences.
#
# Re-fires _out/manifest_resample.json N times at <after-ref> and N times at
# <before-ref>, restarting the server before every run so fakeredis is empty
# and each sample is genuinely cache-cold.
#
# If one fixed build produces more than one distinct response for a request
# across its N cold samples, that request is nondeterministic -- and a
# before/after difference on it cannot be attributed to the commit range. This
# is how a 2-sample "the after-ref reproduced itself" attribution gets
# confirmed or overturned.
#
# Writes capture_resAFTER_r1..rN.json and capture_resBEFORE_r1..rN.json.
set -u

BEFORE_REF="${1:?usage: resample.sh <before-ref> <after-ref> [runs]}"
AFTER_REF="${2:?usage: resample.sh <before-ref> <after-ref> [runs]}"
RUNS="${3:-6}"

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT="$(cd "$HERE/../../.." && pwd)"
OUT="$HERE/_out"
PY="$ROOT/.venv/bin/python"
SUBMANIFEST="$OUT/manifest_resample.json"
BASE_URL="http://127.0.0.1:5000"
# Staged copies that survive the `git checkout`s to <before-ref> / <after-ref>
# (see run.sh).
SERVE_PY="$OUT/_staged_serve.py"
REPLAY_PY="$OUT/_staged_replay.py"

cd "$ROOT"
ORIG_REF="$(git symbolic-ref --short -q HEAD 2>/dev/null || git rev-parse HEAD)"
log() { echo "[resample $(date +%H:%M:%S)] $*"; }
fail() { log "ERROR: $*"; exit 1; }

[ -f "$SUBMANIFEST" ] || fail "missing $SUBMANIFEST -- build it first"

stage_scripts() {
  # Copy the version-independent harness scripts into _out/ so they survive the
  # `git checkout`s below, which may delete this directory.
  cp "$HERE/serve.py"  "$SERVE_PY"  || fail "cannot stage serve.py"
  cp "$HERE/replay.py" "$REPLAY_PY" || fail "cannot stage replay.py"
}

start_server() {
  ENDPOINT_DIFF_OUT="$OUT" ENDPOINT_DIFF_ROOT="$ROOT" nohup "$PY" "$SERVE_PY" \
    > "$OUT/server_resample.log" 2>&1 &
  echo $! > "$OUT/server.pid"
  for _ in $(seq 1 90); do
    curl -sf "$BASE_URL/hello/" >/dev/null 2>&1 && return 0
    sleep 1
  done
  cat "$OUT/server_resample.log"
  fail "server did not become ready"
}

stop_server() {
  [ -f "$OUT/server.pid" ] && kill "$(cat "$OUT/server.pid")" 2>/dev/null
  pkill -f "_staged_serve.py" 2>/dev/null
  rm -f "$OUT/server.pid"
  sleep 2
}

cleanup() {
  stop_server
  local now
  now="$(git symbolic-ref --short -q HEAD 2>/dev/null || git rev-parse HEAD)"
  if [ "$now" != "$ORIG_REF" ]; then
    log "restoring working tree to $ORIG_REF"
    git checkout --quiet "$ORIG_REF" || log "WARNING: failed to restore $ORIG_REF"
  fi
}
trap cleanup EXIT

sample_build() {  # $1 = label prefix
  local rev
  rev="$(git rev-parse HEAD)"
  log "$1: $RUNS cold-cache runs at $(git rev-parse --short HEAD)"
  for k in $(seq 1 "$RUNS"); do
    start_server
    "$PY" "$REPLAY_PY" --manifest "$SUBMANIFEST" --label "${1}_r${k}" \
      --base-url "$BASE_URL" --concurrency 15 --git-rev "$rev" --out "$OUT" \
      > /dev/null 2>&1 || log "WARNING: replay $1 r$k returned non-zero"
    stop_server
    log "  $1 run $k/$RUNS complete"
  done
}

stage_scripts
log "checking out $AFTER_REF"
git checkout --quiet "$AFTER_REF" || fail "git checkout $AFTER_REF failed"
sample_build resAFTER
log "checking out $BEFORE_REF"
git checkout --quiet "$BEFORE_REF" || fail "git checkout $BEFORE_REF failed"
sample_build resBEFORE
git checkout --quiet "$ORIG_REF" || fail "could not restore $ORIG_REF"
log "restored $ORIG_REF"
log "done"
