#!/usr/bin/env bash
# Bash harness for vnc.sh `cdp-liveness` — the standing Chromium respawn
# supervisor (Task 1191).
#
# The supervisor reconciles expected-vs-actual: when the VNC display is up but
# the automation Chromium's CDP port is unreachable, it re-runs the brand's
# start_chrome path so a Chromium that died is restored WITHOUT a brand-service
# restart, bounded so an unlaunchable Chromium never hot-loops.
#
# Determinism without a real browser or real ports: the test injects three
# fakes onto the PATH used FOR THE vnc.sh SUBPROCESS ONLY (never the harness's
# own PATH):
#   ss            — reports a port as LISTEN iff it appears in $STATE_DIR/ports.
#   sleep         — collapses vnc.sh's port-wait loop to ~0.02s/iteration.
#   chromium-stub — records each launch in $STATE_DIR/chromium-calls and, in
#                   "ready" mode, writes the CDP port into $STATE_DIR/ports so
#                   the next ss probe sees it. "fail" mode never opens the port.
# RESPAWN_MAX_FAILS / RESPAWN_COOLDOWN_SECS are passed to vnc.sh so the backoff
# state machine is exercised without waiting real minutes.
#
# Covers the Task 1191 verification surface:
#   1. CDP reachable                 → reachable=true, zero respawns (no-op).
#   2. display up + CDP unreachable   → exactly one start_chrome, outcome=ready.
#   3. repeated unreachable cycles    → respawn capped at MAX, then cooldown
#                                       (no hot-loop on an unlaunchable browser).
#   4. cooldown elapses               → one further respawn attempt (not stuck).
#   5. native DISPLAY_MODE            → no line emitted, zero respawns.

set -uo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
VNC_SH="$(cd "$SCRIPT_DIR/.." && pwd)/vnc.sh"
if [[ ! -f "$VNC_SH" ]]; then
  echo "FATAL: $VNC_SH not found" >&2
  exit 1
fi
if ! command -v jq >/dev/null 2>&1; then
  echo "SKIP: jq not on PATH — cannot run vnc.sh brand resolution" >&2
  exit 0
fi

PASS=0
FAIL=0

# --- per-test scaffolding -------------------------------------------------

CONFIG_DIR=".maxy-cdp-test-$$"
ROOT="/tmp/vnc-cdp-liveness-test-$$"
MAXY_DIR="$HOME/$CONFIG_DIR"
STATE_DIR="$ROOT/state"
FAKE_BIN="$STATE_DIR/bin"

CDP_PORT=59222
RFB_PORT=55900
WS_PORT=56080
VNC_NUM=99

setup() {
  rm -rf "$ROOT" "$MAXY_DIR"
  mkdir -p "$ROOT/platform/scripts" "$ROOT/platform/config" "$STATE_DIR" "$FAKE_BIN" "$MAXY_DIR/logs"
  ln -sf "$VNC_SH" "$ROOT/platform/scripts/vnc.sh"

  cat > "$ROOT/platform/config/brand.json" <<JSON
{
  "configDir": "$CONFIG_DIR",
  "hostname": "maxy-cdp-test",
  "vncDisplay": $VNC_NUM,
  "rfbPort": $RFB_PORT,
  "websockifyPort": $WS_PORT,
  "cdpPort": $CDP_PORT
}
JSON

  # chromium-binary.path → the stub (a non-snap, executable path).
  echo "$FAKE_BIN/chromium-stub" > "$ROOT/platform/config/chromium-binary.path"

  : > "$STATE_DIR/ports"
  echo "$CDP_PORT" > "$STATE_DIR/cdp-port"
  echo "ready" > "$STATE_DIR/chromium-mode"
  : > "$STATE_DIR/chromium-calls"

  # Fake ss: LISTEN line iff the requested port is in $STATE_DIR/ports.
  cat > "$FAKE_BIN/ss" <<'SS'
#!/usr/bin/env bash
port=$(printf '%s\n' "$*" | grep -oE 'sport = :[0-9]+' | grep -oE '[0-9]+$')
[ -z "$port" ] && exit 0
if [ -f "$STATE_DIR/ports" ] && grep -qx "$port" "$STATE_DIR/ports"; then
  echo "LISTEN 0 128 127.0.0.1:$port 0.0.0.0:*"
fi
exit 0
SS

  # Fake sleep: collapse vnc.sh's 0.3s waits so the port-wait loop is fast.
  cat > "$FAKE_BIN/sleep" <<'SLEEP'
#!/usr/bin/env bash
exec /bin/sleep 0.02
SLEEP

  # Stub Chromium: record the launch; in "ready" mode open the CDP port.
  cat > "$FAKE_BIN/chromium-stub" <<'STUB'
#!/usr/bin/env bash
echo "launch" >> "$STATE_DIR/chromium-calls"
if [ "$(cat "$STATE_DIR/chromium-mode")" = "ready" ]; then
  cat "$STATE_DIR/cdp-port" >> "$STATE_DIR/ports"
fi
exit 0
STUB

  chmod +x "$FAKE_BIN/ss" "$FAKE_BIN/sleep" "$FAKE_BIN/chromium-stub"
}

teardown() {
  rm -rf "$ROOT" "$MAXY_DIR"
}

# Run vnc.sh cdp-liveness with the fakes on PATH (subprocess only). stdout
# carries the op= observability lines; STATE_DIR is shared with the fakes.
run_liveness() {
  STATE_DIR="$STATE_DIR" \
  RESPAWN_MAX_FAILS="${RESPAWN_MAX_FAILS:-3}" \
  RESPAWN_COOLDOWN_SECS="${RESPAWN_COOLDOWN_SECS:-300}" \
  PATH="$FAKE_BIN:$PATH" \
    bash "$ROOT/platform/scripts/vnc.sh" cdp-liveness 2>/dev/null
}

write_env() {
  printf 'DISPLAY_MODE=%s\n' "$1" > "$MAXY_DIR/.env"
}

chromium_calls() { local n; n=$(grep -c . "$STATE_DIR/chromium-calls" 2>/dev/null); echo "${n:-0}"; }
set_ports()      { printf '%s\n' "$@" > "$STATE_DIR/ports"; }
set_mode()       { echo "$1" > "$STATE_DIR/chromium-mode"; }

assert() {
  local desc="$1" cond="$2"
  if [ "$cond" = "1" ]; then
    PASS=$((PASS + 1)); echo "  PASS: $desc"
  else
    FAIL=$((FAIL + 1)); echo "  FAIL: $desc"
  fi
}

# --- Case 1: CDP reachable → no-op ---------------------------------------
case_reachable_noop() {
  echo "=== CASE 1: CDP reachable → reachable=true, no respawn ==="
  setup; write_env virtual
  set_ports "$CDP_PORT" "$RFB_PORT"      # both up
  out="$(run_liveness)"
  assert "emits reachable=true"      "$(echo "$out" | grep -qE 'op=cdp-liveness .*reachable=true' && echo 1 || echo 0)"
  assert "no chromium-respawn line"  "$(echo "$out" | grep -q 'op=chromium-respawn' && echo 0 || echo 1)"
  assert "zero chromium launches"    "$([ "$(chromium_calls)" -eq 0 ] && echo 1 || echo 0)"
  teardown
}

# --- Case 2: display up + CDP down → one respawn, ready ------------------
case_down_respawns_ready() {
  echo "=== CASE 2: display up + CDP down → one respawn, outcome=ready ==="
  setup; write_env virtual
  set_ports "$RFB_PORT"                  # display up, CDP down
  set_mode ready
  out="$(run_liveness)"
  assert "emits reachable=false"          "$(echo "$out" | grep -qE 'op=cdp-liveness .*reachable=false' && echo 1 || echo 0)"
  assert "emits chromium-respawn ready"   "$(echo "$out" | grep -qE 'op=chromium-respawn .*outcome=ready' && echo 1 || echo 0)"
  assert "exactly one chromium launch"    "$([ "$(chromium_calls)" -eq 1 ] && echo 1 || echo 0)"
  teardown
}

# --- Case 3: repeated CDP down → capped respawns (no hot-loop) -----------
case_backoff_no_hotloop() {
  echo "=== CASE 3: repeated CDP down → respawn capped at MAX (no hot-loop) ==="
  setup; write_env virtual
  set_ports "$RFB_PORT"                  # display up, CDP stays down
  set_mode fail                          # every respawn fails to open CDP
  local i
  for i in 1 2 3 4 5; do
    RESPAWN_MAX_FAILS=3 RESPAWN_COOLDOWN_SECS=300 run_liveness >/dev/null
  done
  # 3 attempts then cooldown blocks the 4th and 5th → exactly MAX launches.
  assert "respawn capped at 3 over 5 cycles" "$([ "$(chromium_calls)" -eq 3 ] && echo 1 || echo 0)"
  teardown
}

# --- Case 4: cooldown elapses → one further attempt ----------------------
case_cooldown_retries() {
  echo "=== CASE 4: cooldown elapses → a further respawn is attempted ==="
  setup; write_env virtual
  set_ports "$RFB_PORT"
  set_mode fail
  local i
  for i in 1 2 3; do
    RESPAWN_MAX_FAILS=3 RESPAWN_COOLDOWN_SECS=1 run_liveness >/dev/null
  done
  local before; before="$(chromium_calls)"
  /bin/sleep 1.2                         # let the 1s cooldown elapse (real sleep)
  RESPAWN_MAX_FAILS=3 RESPAWN_COOLDOWN_SECS=1 run_liveness >/dev/null
  local after; after="$(chromium_calls)"
  assert "respawn attempted after cooldown" "$([ "$after" -gt "$before" ] && echo 1 || echo 0)"
  teardown
}

# --- Case 5: native mode → no-op, no line --------------------------------
case_native_noop() {
  echo "=== CASE 5: native DISPLAY_MODE → no line, no respawn ==="
  setup; write_env native
  set_ports "$RFB_PORT"                  # display up, CDP down — normal idle in native
  out="$(run_liveness)"
  assert "emits no op= line"        "$([ -z "$(echo "$out" | grep -E 'op=(cdp-liveness|chromium-respawn)')" ] && echo 1 || echo 0)"
  assert "zero chromium launches"   "$([ "$(chromium_calls)" -eq 0 ] && echo 1 || echo 0)"
  teardown
}

case_reachable_noop
case_down_respawns_ready
case_backoff_no_hotloop
case_cooldown_retries
case_native_noop

echo ""
echo "==================================="
echo "PASS=$PASS FAIL=$FAIL"
echo "==================================="
[ "$FAIL" -eq 0 ]
