#!/usr/bin/env bash
# release-check.sh — pre-release smoke suite for the FORTVISION WP plugin.
#
# Boots a throwaway WordPress (WP Playground, no Docker/MySQL) with the SVN
# trunk mounted as the plugin, then verifies the three things static checks
# can't: the plugin ACTIVATES, the sync collectors execute without SQL errors,
# and the log-endpoint permission matrix behaves. Also php -l's every file
# changed since the last tag.
#
# Usage:  bash release-check.sh            # from anywhere
#         bash release-check.sh --keep     # leave the sandbox running on exit
#
# History: added after the 4.6.24 release, where exactly this suite caught a
# namespace bug (\WP_REST_Request) that php -l and Plugin Check both missed.
set -u
SVN_ROOT="/c/Users/raana/wp-svn/fortvision-platform"
TRUNK_WIN='C:\Users\raana\wp-svn\fortvision-platform\trunk'
PORT=9411
PASS=0; FAIL=0
ok()   { echo "  PASS  $1"; PASS=$((PASS+1)); }
bad()  { echo "  FAIL  $1"; FAIL=$((FAIL+1)); }
# Work dir under the Windows temp root so both Git-bash and the Playground CLI
# (which resolves Windows paths) agree on where files are — a /tmp path gets
# rewritten to C:\tmp and the two disagree.
WORK="$(mktemp -d "${TMP:-/c/Users/raana/AppData/Local/Temp}/rc-XXXXXX")"
WORK_WIN=$(cygpath -w "$WORK" 2>/dev/null || echo "$WORK")
JAR="$WORK/jar.txt"
# Only exclude conversion for the Playground CLI mount args, applied per-call —
# a global MSYS_NO_PATHCONV mangles our own blueprint/-l paths.
PG='npx --yes @wp-playground/cli@latest'

echo "── 1. php -l on files changed since the last tag ──"
# Filesystem listing of the checked-out tags — `svn ls` on the WC can report a
# stale revision that omits freshly-committed tags. Only well-formed X.Y.Z
# (the repo has a stray malformed '4.017' that would otherwise sort last).
LAST_TAG=$(ls "$SVN_ROOT/tags" 2>/dev/null | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -1)
if [ -n "$LAST_TAG" ]; then
  CHANGED=$(cd "$SVN_ROOT" && svn diff --summarize "tags/$LAST_TAG" trunk 2>/dev/null | awk '$1=="M"||$1=="A"{print $2}' | grep '\.php$' | sed 's|.*trunk[/\\]||' | tr '\\' '/')
else
  CHANGED=$(cd "$SVN_ROOT/trunk" && svn status | awk '$1=="M"||$1=="A"{print $2}' | grep '\.php$' | tr '\\' '/')
fi
if [ -z "$CHANGED" ]; then echo "  (no changed .php files vs tags/$LAST_TAG — linting index.php only)"; CHANGED="index.php"; fi
for f in $CHANGED; do
  OUT=$(MSYS2_ARG_CONV_EXCL="*" MSYS_NO_PATHCONV=1 $PG php --mount-dir "$TRUNK_WIN" "/plugin" -- -l "/plugin/$f" 2>&1 | grep -E "No syntax errors|rror" | head -1)
  case "$OUT" in *"No syntax errors"*) ok "lint $f";; *) bad "lint $f — $OUT";; esac
done

echo "── 2. boot sandbox with trunk mounted as the plugin ──"
cat > "$WORK/bp.json" <<'EOF'
{ "steps": [] }
EOF
( MSYS2_ARG_CONV_EXCL="*" MSYS_NO_PATHCONV=1 $PG server --php 8.1 --port $PORT \
   --blueprint="$WORK_WIN\\bp.json" \
   --mount-dir "$TRUNK_WIN" "/wordpress/wp-content/plugins/fortvision-platform" \
   > "$WORK/server.log" 2>&1 &)
SERVER_UP=""
for i in $(seq 1 30); do
  sleep 3
  CODE=$(curl -s -o /dev/null -w '%{http_code}' -m 5 "http://127.0.0.1:$PORT/wp-login.php" 2>/dev/null)
  [ "$CODE" = "200" ] && SERVER_UP=1 && break
done
if [ -z "$SERVER_UP" ]; then bad "sandbox did not come up on :$PORT (see $WORK/server.log)"; echo "RESULT: $PASS pass, $((FAIL)) fail"; exit 1; fi
ok "sandbox up on :$PORT"

# Admin login (Playground's fixed sandbox creds).
curl -s -c "$JAR" -o /dev/null "http://127.0.0.1:$PORT/wp-login.php"
curl -s -b "$JAR" -c "$JAR" -o /dev/null -d "log=admin&pwd=password&wp-submit=Log+In&redirect_to=%2Fwp-admin%2F" "http://127.0.0.1:$PORT/wp-login.php"

echo "── 3. activation ──"
curl -s -b "$JAR" "http://127.0.0.1:$PORT/wp-admin/plugins.php" -o "$WORK/plugins.html"
ACT=$(grep -oE 'plugins\.php\?action=activate&amp;plugin=fortvision-platform[^"]*' "$WORK/plugins.html" | head -1 | sed 's/&amp;/\&/g')
[ -n "$ACT" ] && curl -s -b "$JAR" -o /dev/null "http://127.0.0.1:$PORT/wp-admin/$ACT"
curl -s -b "$JAR" "http://127.0.0.1:$PORT/wp-admin/plugins.php" -o "$WORK/plugins2.html"
if grep -q "fortvision-deactivate-survey-modal" "$WORK/plugins2.html"; then ok "plugin active (hooks render)"; else bad "plugin did not activate — check $WORK/plugins2.html"; fi
if grep -qE "Plugin could not be activated|unexpected output" "$WORK/plugins2.html"; then bad "activation produced errors"; else ok "no activation errors / unexpected output"; fi

# The sandbox site lives in a real temp dir — find it to drop test scripts.
SITE=$(ls -dt "$TMP"/node.exe-playground-cli-site-* 2>/dev/null | head -1)
if [ -z "$SITE" ]; then bad "could not locate the sandbox site dir"; echo "RESULT: $PASS pass, $FAIL fail"; exit 1; fi

echo "── 4. sync collectors execute (no SQL errors) ──"
cat > "$SITE/wordpress/test-fv-sql.php" <<'EOF'
<?php
require __DIR__ . '/wp-load.php';
if ( ! current_user_can( 'manage_options' ) ) { http_response_code(403); exit; }
global $wpdb; header( 'Content-Type: text/plain' );
$new = new \Fortvision\FortvisionDbSync();
$ref = new ReflectionClass( $new );
foreach ( array(
	array( 'collect_contacts', 0, '', true ), array( 'collect_contacts', 5, '2024-01-01 00:00:00', false ),
	array( 'collect_orders', 0, '', true ),   array( 'collect_orders', 5, '2024-01-01 00:00:00', false ),
	array( 'collect_products', 0, '', true ), array( 'collect_products', 5, '2024-01-01 00:00:00', false ),
	array( 'collect_productVariants', 3, '', true ),
) as $c ) {
	if ( ! $ref->hasMethod( $c[0] ) ) { echo "SKIP {$c[0]}\n"; continue; }
	$wpdb->last_error = '';
	try { $m = $ref->getMethod( $c[0] ); $m->setAccessible( true ); $m->invoke( $new, $c[1], $c[2], $c[3] );
		echo ( $wpdb->last_error ? "SQLERR {$c[0]}: {$wpdb->last_error}" : "OK {$c[0]}" ), "\n";
	} catch ( Throwable $e ) { echo "THROW {$c[0]}: " . $e->getMessage() . "\n"; }
}
EOF
COLL=$(curl -s -b "$JAR" -m 60 "http://127.0.0.1:$PORT/test-fv-sql.php")
echo "$COLL" | sed 's/^/       /'
if echo "$COLL" | grep -qE "SQLERR|THROW"; then bad "collector errors above"; else
  N=$(echo "$COLL" | grep -c '^OK'); [ "$N" -ge 7 ] && ok "all $N collector runs clean" || bad "only $N/7 collector runs completed"; fi

echo "── 5. log-endpoint permission matrix ──"
cat > "$SITE/wordpress/test-fv-auth.php" <<'EOF'
<?php
require __DIR__ . '/wp-load.php';
if ( ! current_user_can( 'manage_options' ) ) { http_response_code(403); exit; }
update_option( 'fortvision_leads_events_key', 'rc-smoke-key' );
header( 'Content-Type: application/json' );
echo json_encode( array( 'nonce' => wp_create_nonce( 'wp_rest' ) ) );
EOF
NONCE=$(curl -s -b "$JAR" "http://127.0.0.1:$PORT/test-fv-auth.php" | grep -oE '"nonce":"[^"]+"' | cut -d'"' -f4)
# Anonymous jar: Playground needs its own session cookie or every request 302-loops.
AJ="$WORK/anon.txt"; curl -s -L --max-redirs 3 -c "$AJ" -o /dev/null "http://127.0.0.1:$PORT/"
R="http://127.0.0.1:$PORT/index.php?rest_route=/fortvision/v1"
t() { curl -s -b "$AJ" -o /dev/null -w '%{http_code}' -m 20 "$1"; }
C1=$(t "$R/get_main_log");                 [ "$C1" = "401" ] || [ "$C1" = "403" ] && ok "anon denied ($C1)"        || bad "anon got $C1 (want 401/403)"
C2=$(t "$R/get_main_log&key=wrong");       [ "$C2" = "401" ] || [ "$C2" = "403" ] && ok "wrong key denied ($C2)"   || bad "wrong key got $C2 (want 401/403)"
C3=$(t "$R/get_main_log&key=rc-smoke-key"); [ "$C3" = "200" ] && ok "correct key allowed"                          || bad "correct key got $C3 (want 200)"
C4=$(curl -s -b "$JAR" -H "X-WP-Nonce: $NONCE" -o /dev/null -w '%{http_code}' -m 20 "$R/get_main_log"); [ "$C4" = "200" ] && ok "admin allowed" || bad "admin got $C4 (want 200)"
C5=$(t "$R/logs_get&key=rc-smoke-key");    [ "$C5" = "200" ] && ok "logs_get with key allowed"                     || bad "logs_get key got $C5 (want 200)"
rm -f "$SITE/wordpress/test-fv-sql.php" "$SITE/wordpress/test-fv-auth.php"

echo
echo "RESULT: $PASS pass, $FAIL fail"
if [ "${1:-}" != "--keep" ]; then
  # Kill the sandbox: the node process serving our port.
  PIDLINE=$(netstat -ano 2>/dev/null | grep ":$PORT " | grep LISTENING | head -1)
  PID=$(echo "$PIDLINE" | awk '{print $NF}')
  [ -n "${PID:-}" ] && taskkill //F //PID "$PID" >/dev/null 2>&1 && echo "(sandbox stopped)"
fi
[ "$FAIL" -eq 0 ] || exit 1
