#!/usr/bin/env bash
# VPN crash simulation lab — device (adb) and/or BE upload verification.
#
# Modes:
#   MODE=device  — trigger VpnCrashSimulator in :vpn via adb (debug APK)
#   MODE=upload  — POST synthetic vpn-process crash JSON to BE upload API
#   MODE=both    — device then verify BE (default when adb device present)
#
# Env:
#   COUNT=70
#   BASE=https://apps.f0xx.org/app/androidcast_project/crashes
#   RUN_ID=YYYYMMDD_HHMMSS (batch tag for Issues search)
#   PACKAGE=com.foxx.androidcast
set -euo pipefail

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
COUNT="${COUNT:-70}"
BASE="${BASE:-https://apps.f0xx.org/app/androidcast_project/crashes}"
UPLOAD_URL="$BASE/api/upload.php"
PACKAGE="${PACKAGE:-com.foxx.androidcast}"
RUN_ID="${RUN_ID:-$(date -u +%Y%m%d_%H%M%S)}"
MODE="${MODE:-auto}"
JAR="${JAR:-/tmp/ac_vpn_crash_cookies.txt}"
DELAY_MS="${DELAY_MS:-80}"
VERIFY_LOGIN="${VERIFY_LOGIN:-1}"

log() { printf '[vpn-crash-sim] %s\n' "$*"; }

has_device() {
  adb devices 2>/dev/null | awk 'NR>1 && $2=="device" { found=1 } END { exit !found }'
}

simulate_device() {
  local n="$1"
  local i seq
  log "device: triggering $n VPN-process crash recordings via $PACKAGE"
  for ((i = 1; i <= n; i++)); do
    seq="$i"
    adb shell am start-service \
      -n "$PACKAGE/com.foxx.androidcast.vpn.AndroidCastVpnService" \
      -a com.foxx.androidcast.vpn.SIMULATE_CRASH \
      --ei sim_seq "$seq" >/dev/null 2>&1 \
      || adb shell am startservice \
      -n "$PACKAGE/com.foxx.androidcast.vpn.AndroidCastVpnService" \
      -a com.foxx.androidcast.vpn.SIMULATE_CRASH \
      --ei sim_seq "$seq" >/dev/null 2>&1 \
      || true
    if [[ "$DELAY_MS" -gt 0 ]]; then
      sleep "$(awk "BEGIN { print $DELAY_MS / 1000 }")"
    fi
    if (( i % 10 == 0 )); then
      log "  device progress $i/$n"
    fi
  done
  log "device: done — waiting for crash watcher upload sweep"
  sleep 15
}

upload_one() {
  local seq="$1"
  local report_id="vpn_sim_${RUN_ID}_$(printf '%03d' "$seq")"
  local ms
  ms="$(date +%s)000"
  local fp
  fp="$(printf 'vpn_sim_%s_%03d' "$RUN_ID" "$seq" | sha256sum | awk '{print $1}')"
  local body
  body="$(cat <<EOF
{
  "schema_version": 1,
  "report_id": "$report_id",
  "generated_at_epoch_ms": $ms,
  "crash_type": "java",
  "scenario": "vpn_service",
  "process": "com.foxx.androidcast:vpn",
  "fingerprint": "$fp",
  "tags": ["vpn_sim", "$RUN_ID"],
  "device": {
    "manufacturer": "SimLab",
    "brand": "AndroidCast",
    "model": "VpnCrashSim",
    "device": "vpn_sim",
    "product": "vpn_sim",
    "sdk_int": 34,
    "release": "14",
    "abis": ["arm64-v8a"]
  },
  "app": {
    "package": "$PACKAGE",
    "version_name": "0.1.0",
    "version_code": 100
  },
  "build": { "debug": true, "git_commit": "vpn_sim" },
  "runtime_context": { "vpn_sim_seq": $seq, "run_id": "$RUN_ID" },
  "java": {
    "thread": "androidcast-vpn-worker",
    "exception": "java.lang.RuntimeException",
    "message": "VpnCrashSimulation seq=$seq proc=com.foxx.androidcast:vpn",
    "stack_frames": [
      "com.foxx.androidcast.vpn.WireGuardVpnEngine.apply(WireGuardVpnEngine.java:40)",
      "com.foxx.androidcast.vpn.AndroidCastVpnService\$1.applyWireGuardConfig(AndroidCastVpnService.java:60)",
      "com.foxx.androidcast.vpn.AndroidCastVpnService.onStartCommand(AndroidCastVpnService.java:95)",
      "android.app.ActivityThread.handleServiceArgs(ActivityThread.java:5001)"
    ]
  }
}
EOF
)"
  curl -sk -w '\n%{http_code}' -H 'Content-Type: application/json' --data-binary "$body" "$UPLOAD_URL"
}

simulate_upload() {
  local n="$1"
  local ok=0 fail=0 dup=0
  log "upload: posting $n vpn-process crash reports to $UPLOAD_URL (run_id=$RUN_ID)"
  local i resp code
  for ((i = 1; i <= n; i++)); do
    resp="$(upload_one "$i")"
    code="$(echo "$resp" | tail -n1)"
    case "$code" in
      200) ((ok++)) || true ;;
      409) ((dup++)) || true ;;
      *) ((fail++)) || true; log "  FAIL seq=$i HTTP $code" ;;
    esac
    if (( i % 10 == 0 )); then
      log "  upload progress $i/$n (ok=$ok dup=$dup fail=$fail)"
    fi
    if [[ "$DELAY_MS" -gt 0 ]]; then
      sleep "$(awk "BEGIN { print $DELAY_MS / 1000 }")"
    fi
  done
  log "upload: ok=$ok duplicate=$dup failed=$fail / $n"
  [[ "$fail" -eq 0 ]]
}

verify_be() {
  if [[ "$VERIFY_LOGIN" != "1" ]]; then
    log "verify: skipped (VERIFY_LOGIN=$VERIFY_LOGIN)"
    return 0
  fi
  log "verify: login + search Issues for run_id=$RUN_ID"
  curl -sk -c "$JAR" -b "$JAR" -L -X POST "$BASE/login" \
    -d 'username=admin&password=admin' -o /dev/null || true
  local json
  local q="${QUERY:-$RUN_ID}"
  json="$(curl -sk -b "$JAR" "$BASE/api/reports.php?q=${q}&per_page=200")"
  local cnt
  cnt="$(echo "$json" | python3 -c "
import json,sys
d=json.load(sys.stdin)
items=d.get('items') or []
print(len(items))
" 2>/dev/null || echo 0)"
  log "verify: BE reports matching q=$q → $cnt (expected up to $COUNT)"
  if [[ "$cnt" -lt 1 ]]; then
    log "verify: WARN — Issues API returned 0 (login cookie may be invalid in automation)"
    log "verify: open $BASE/?view=reports&q=$q in browser when logged in"
    return 1
  fi
  echo "$json" | python3 -c "
import json,sys
d=json.load(sys.stdin)
for it in (d.get('items') or [])[:3]:
    p=it.get('payload') or {}
    j=p.get('java') or {}
    print(' sample:', it.get('report_id'), 'process=', p.get('process'), 'frames=', len(j.get('stack_frames') or []))
" 2>/dev/null || true
}

if [[ "$MODE" == "auto" ]]; then
  if has_device; then
    MODE=both
  else
    MODE=upload
    log "no adb device — using upload-only mode"
  fi
fi

case "$MODE" in
  device)
    simulate_device "$COUNT"
    ;;
  upload)
    simulate_upload "$COUNT"
    verify_be || true
    ;;
  both)
    simulate_device "$COUNT"
    QUERY="${QUERY:-VpnCrashSimulation}" verify_be || true
    ;;
  *)
    echo "unknown MODE=$MODE (device|upload|both)" >&2
    exit 1
    ;;
esac

log "complete run_id=$RUN_ID — Issues: $BASE/?view=reports&q=$RUN_ID"
