# Shared helpers for the iteras cache-busting test harness.
# Sourced by test-cache-busting.sh and test-with-cache-plugin.sh.
#
# Requires: bash, curl, openssl (unused but kept as a dependency note), php (CLI),
#           wp-cli on PATH, a running WordPress with the iteras plugin active.

set -u

# --- Configuration (override via env or tests/.env) ---
if [ -f "$(dirname "${BASH_SOURCE[0]}")/.env" ]; then
  # shellcheck disable=SC1091
  source "$(dirname "${BASH_SOURCE[0]}")/.env"
fi

: "${SITE_URL:?SITE_URL must be set (e.g. http://localhost:8080)}"
: "${WP_PATH:?WP_PATH must be set to the WordPress install directory}"
: "${SIGNING_KEY:=test-signing-key-1234567890abcdef}"
: "${PAYWALL_ID:=test-paywall}"

CACHE_BUST_REGEX='cache-control:.*(no-store|no-cache|private)'

# --- Counters ---
PASSED=0
FAILED=0
FAIL_LOG=()

# --- Pretty output ---
if [ -t 1 ]; then
  C_RED=$'\033[31m'; C_GREEN=$'\033[32m'; C_YELLOW=$'\033[33m'; C_DIM=$'\033[2m'; C_RESET=$'\033[0m'
else
  C_RED=''; C_GREEN=''; C_YELLOW=''; C_DIM=''; C_RESET=''
fi

log()  { echo "${C_DIM}$*${C_RESET}"; }
info() { echo "${C_YELLOW}$*${C_RESET}"; }
pass() { PASSED=$((PASSED+1)); echo "  ${C_GREEN}PASS${C_RESET} $1"; }
fail() {
  FAILED=$((FAILED+1))
  FAIL_LOG+=("$1")
  echo "  ${C_RED}FAIL${C_RESET} $1"
  [ -n "${2:-}" ] && echo "${C_DIM}    $2${C_RESET}"
}

# --- WP helper wrapper (replaces wp-cli for the limited subset we need) ---
WP_HELPER="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/wp-helper.php"
wph() {
  WP_PATH="$WP_PATH" php "$WP_HELPER" "$@"
}

# --- Cookie generator: mirrors Iteras::pass_authorized() ---
# Args: access_level paywall_id ttl_seconds [signing_key]
# Outputs the cookie value: "access|paywall|expiry/sha256:hmac"
gen_iteraspass() {
  local access="$1" paywall="$2" ttl="${3:-3600}"
  local signing="${4:-$SIGNING_KEY}"
  php -r '
    $access = $argv[1];
    $paywall = $argv[2];
    $ttl = (int)$argv[3];
    $signing = $argv[4];
    $data = $access . "|" . $paywall . "|" . date("Y-m-d\TH:i:s", time() + $ttl);
    $hmac = hash_hmac("sha256", $data, $signing);
    echo $data . "/sha256:" . $hmac;
  ' "$access" "$paywall" "$ttl" "$signing"
}

# --- HTTP helpers ---
# fetch_headers URL [COOKIE_VALUE]
fetch_headers() {
  local url="$1" cookie="${2:-}"
  if [ -n "$cookie" ]; then
    curl -sI -b "iteraspass=$cookie" "$url" | tr '[:upper:]' '[:lower:]'
  else
    curl -sI "$url" | tr '[:upper:]' '[:lower:]'
  fi
}

# fetch_body URL [COOKIE_VALUE]
fetch_body() {
  local url="$1" cookie="${2:-}"
  if [ -n "$cookie" ]; then
    curl -sL -b "iteraspass=$cookie" "$url"
  else
    curl -sL "$url"
  fi
}

# --- Assertions ---
# assert_headers_match HEADERS REGEX LABEL
assert_headers_match() {
  local headers="$1" regex="$2" label="$3"
  if echo "$headers" | grep -Eq "$regex"; then
    pass "$label"
  else
    fail "$label" "expected header matching /$regex/; got:"
    echo "$headers" | sed 's/^/      /'
  fi
}

# assert_headers_not_match HEADERS REGEX LABEL
assert_headers_not_match() {
  local headers="$1" regex="$2" label="$3"
  if echo "$headers" | grep -Eq "$regex"; then
    fail "$label" "did not expect header matching /$regex/; got:"
    echo "$headers" | sed 's/^/      /'
  else
    pass "$label"
  fi
}

# assert_body_contains BODY NEEDLE LABEL
assert_body_contains() {
  local body="$1" needle="$2" label="$3"
  if echo "$body" | grep -qF "$needle"; then
    pass "$label"
  else
    fail "$label" "expected body to contain '$needle'"
  fi
}

assert_body_not_contains() {
  local body="$1" needle="$2" label="$3"
  if echo "$body" | grep -qF "$needle"; then
    fail "$label" "body unexpectedly contained '$needle'"
  else
    pass "$label"
  fi
}

# --- Fixture management ---
FIXTURES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/fixtures" && pwd)"
MU_DIR="$WP_PATH/wp-content/mu-plugins"

setup_fixtures() {
  mkdir -p "$MU_DIR"
  ln -sf "$FIXTURES_DIR/override-filter.php" "$MU_DIR/iteras-test-override-filter.php"
  # Reset counter file
  rm -f /tmp/iteras_test_counter.txt
  echo 0 > /tmp/iteras_test_counter.txt
  chmod 666 /tmp/iteras_test_counter.txt
}

teardown_fixtures() {
  rm -f "$MU_DIR/iteras-test-override-filter.php"
  rm -f /tmp/iteras_test_counter.txt
  rm -f /tmp/iteras_test_override_off_post_id.txt
}

read_filter_counter() {
  cat /tmp/iteras_test_counter.txt 2>/dev/null || echo 0
}

reset_filter_counter() {
  echo 0 > /tmp/iteras_test_counter.txt
}

# --- Settings snapshot/restore ---
SETTINGS_BACKUP=/tmp/iteras_settings_backup.json

backup_settings() {
  wph get-option iteras_settings > "$SETTINGS_BACKUP"
}

restore_settings() {
  if [ -f "$SETTINGS_BACKUP" ]; then
    wph set-option-json iteras_settings < "$SETTINGS_BACKUP" > /dev/null
    rm -f "$SETTINGS_BACKUP"
  fi
}

set_known_settings() {
  # SSV on, prevent-caching on, known signing_key, one paywall configured
  local json
  json=$(php -r '
    echo json_encode(array(
      "signing_key" => $argv[1],
      "api_key" => $argv[1],
      "profile_name" => "test",
      "paywall_id" => "",
      "subscribe_url" => "https://example.com/subscribe",
      "user_url" => "https://example.com/account",
      "default_access" => "",
      "paywalls" => array(array("paywall_id" => $argv[2], "name" => "Test")),
      "paywall_integration_method" => "auto",
      "paywall_server_side_validation" => true,
      "paywall_prevent_caching" => true,
      "paywall_display_type" => "redirect",
      "paywall_box" => "<p>Subscribe</p>",
      "paywall_snippet_size" => 300,
      "version" => "1.8.4",
    ));
  ' "$SIGNING_KEY" "$PAYWALL_ID")
  echo "$json" | wph set-option-json iteras_settings > /dev/null
}

# --- Posts ---
POST_A_FILE=/tmp/iteras_test_post_a.txt
POST_B_FILE=/tmp/iteras_test_post_b.txt
POST_C_FILE=/tmp/iteras_test_post_c.txt
POST_D_FILE=/tmp/iteras_test_post_d.txt   # control: extra non-paywalled post for "clean feed" tests

create_test_posts() {
  local a b c d
  a=$(wph post-create 'ITERAS Test A unpaywalled' '<p>Plain article without paywall, with enough body content to be visually distinguishable from a truncated version when fetched over HTTP.</p>')
  b=$(wph post-create 'ITERAS Test B paywalled' '<p>Paywalled article body. This content should be truncated for anonymous visitors and visible only to subscribers with a valid iteraspass cookie. Sentinel marker: ITERAS_FULL_BODY_B.</p>')
  c=$(wph post-create 'ITERAS Test C override-off paywalled' '<p>Paywalled in meta, but an override filter forces it to be treated as unpaywalled. Sentinel: ITERAS_FULL_BODY_C.</p>')
  d=$(wph post-create 'ITERAS Test D unpaywalled control' '<p>Another unpaywalled post used for clean-feed scenarios. UNIQUE_MARKER_ITERAS_CLEAN_FEED_SENTINEL.</p>')

  wph post-meta-set-json "$b" iteras_paywall "[\"$PAYWALL_ID\"]" > /dev/null
  wph post-meta-set-json "$c" iteras_paywall "[\"$PAYWALL_ID\"]" > /dev/null

  echo "$a" > "$POST_A_FILE"
  echo "$b" > "$POST_B_FILE"
  echo "$c" > "$POST_C_FILE"
  echo "$d" > "$POST_D_FILE"
  echo "$c" > /tmp/iteras_test_override_off_post_id.txt
}

delete_test_posts() {
  for f in "$POST_A_FILE" "$POST_B_FILE" "$POST_C_FILE" "$POST_D_FILE"; do
    [ -f "$f" ] || continue
    local id
    id=$(cat "$f")
    [ -n "$id" ] && wph post-delete "$id" > /dev/null 2>&1 || true
    rm -f "$f"
  done
}

post_permalink() {
  local id="$1"
  wph post-url "$id"
}

# --- Top-level setup / teardown ---
setup_state() {
  info "Backing up settings, installing fixtures, creating test posts..."
  backup_settings
  set_known_settings
  setup_fixtures
  create_test_posts
}

teardown_state() {
  info "Tearing down: deleting test posts, removing fixtures, restoring settings..."
  delete_test_posts
  teardown_fixtures
  restore_settings
}

# --- Summary ---
print_summary() {
  echo
  echo "----------------------------------------"
  if [ "$FAILED" -eq 0 ]; then
    echo "${C_GREEN}$PASSED passed, 0 failed${C_RESET}"
  else
    echo "${C_RED}$PASSED passed, $FAILED failed${C_RESET}"
    echo "Failures:"
    for f in "${FAIL_LOG[@]}"; do echo "  - $f"; done
  fi
  echo "----------------------------------------"
}
