#!/usr/bin/env bash
# identity-on-sx conformance runner.
#
# Loads the Erlang-on-SX substrate, the identity library, and every
# identity test suite via the epoch protocol, collects pass/fail counts,
# and writes lib/identity/scoreboard.json + .md.
#
# Usage:
#   bash lib/identity/conformance.sh        # run all suites
#   bash lib/identity/conformance.sh -v     # verbose per-suite

set -uo pipefail
cd "$(git rev-parse --show-toplevel)"

SX_SERVER="${SX_SERVER:-hosts/ocaml/_build/default/bin/sx_server.exe}"
if [ ! -x "$SX_SERVER" ]; then
  SX_SERVER="/root/rose-ash/hosts/ocaml/_build/default/bin/sx_server.exe"
fi
if [ ! -x "$SX_SERVER" ]; then
  echo "ERROR: sx_server.exe not found." >&2
  exit 1
fi

VERBOSE="${1:-}"
TMPFILE=$(mktemp)
OUTFILE=$(mktemp)
trap "rm -f $TMPFILE $OUTFILE" EXIT

# Each suite: name | counter pass | counter total
SUITES=(
  "session|id-session-test-pass|id-session-test-count"
  "token|id-token-test-pass|id-token-test-count"
  "registry|id-registry-test-pass|id-registry-test-count"
  "api|id-api-test-pass|id-api-test-count"
  "oauth|id-oauth-test-pass|id-oauth-test-count"
  "sso|id-sso-test-pass|id-sso-test-count"
  "membership|id-membership-test-pass|id-membership-test-count"
  "cache|id-cache-test-pass|id-cache-test-count"
  "audit|id-audit-test-pass|id-audit-test-count"
  "federation|id-fed-test-pass|id-fed-test-count"
  "expiry|id-expiry-test-pass|id-expiry-test-count"
  "clients|id-clients-test-pass|id-clients-test-count"
  "grants|id-grants-test-pass|id-grants-test-count"
  "device|id-device-test-pass|id-device-test-count"
  "facade|id-facade-test-pass|id-facade-test-count"
  "delegation|id-deleg-test-pass|id-deleg-test-count"
  "session-mgmt|id-smgmt-test-pass|id-smgmt-test-count"
  "exchange|id-xchg-test-pass|id-xchg-test-count"
  "introspect|id-intr-test-pass|id-intr-test-count"
  "par|id-par-test-pass|id-par-test-count"
  "dynreg|id-dyn-test-pass|id-dyn-test-count"
  "account|id-acct-test-pass|id-acct-test-count"
  "pkce|id-pkce-test-pass|id-pkce-test-count"
)

cat > "$TMPFILE" << 'EPOCHS'
(epoch 1)
(load "lib/erlang/tokenizer.sx")
(load "lib/erlang/parser.sx")
(load "lib/erlang/parser-core.sx")
(load "lib/erlang/parser-expr.sx")
(load "lib/erlang/parser-module.sx")
(load "lib/erlang/transpile.sx")
(load "lib/erlang/runtime.sx")
(load "lib/identity/session.sx")
(load "lib/identity/token.sx")
(load "lib/identity/registry.sx")
(load "lib/identity/api.sx")
(load "lib/identity/oauth.sx")
(load "lib/identity/membership.sx")
(load "lib/identity/cache.sx")
(load "lib/identity/audit.sx")
(load "lib/identity/federation.sx")
(load "lib/identity/clients.sx")
(load "lib/identity/device.sx")
(load "lib/identity/delegation.sx")
(load "lib/identity/tests/session.sx")
(load "lib/identity/tests/token.sx")
(load "lib/identity/tests/registry.sx")
(load "lib/identity/tests/api.sx")
(load "lib/identity/tests/oauth.sx")
(load "lib/identity/tests/sso.sx")
(load "lib/identity/tests/membership.sx")
(load "lib/identity/tests/cache.sx")
(load "lib/identity/tests/audit.sx")
(load "lib/identity/tests/federation.sx")
(load "lib/identity/tests/expiry.sx")
(load "lib/identity/tests/clients.sx")
(load "lib/identity/tests/grants.sx")
(load "lib/identity/tests/device.sx")
(load "lib/identity/tests/facade.sx")
(load "lib/identity/tests/delegation.sx")
(load "lib/identity/tests/session_mgmt.sx")
(load "lib/identity/tests/exchange.sx")
(load "lib/identity/tests/introspect.sx")
(load "lib/identity/tests/par.sx")
(load "lib/identity/tests/dynreg.sx")
(load "lib/identity/tests/account.sx")
(load "lib/identity/tests/pkce.sx")
(epoch 100)
(eval "(list id-session-test-pass id-session-test-count)")
(epoch 101)
(eval "(list id-token-test-pass id-token-test-count)")
(epoch 102)
(eval "(list id-registry-test-pass id-registry-test-count)")
(epoch 103)
(eval "(list id-api-test-pass id-api-test-count)")
(epoch 104)
(eval "(list id-oauth-test-pass id-oauth-test-count)")
(epoch 105)
(eval "(list id-sso-test-pass id-sso-test-count)")
(epoch 106)
(eval "(list id-membership-test-pass id-membership-test-count)")
(epoch 107)
(eval "(list id-cache-test-pass id-cache-test-count)")
(epoch 108)
(eval "(list id-audit-test-pass id-audit-test-count)")
(epoch 109)
(eval "(list id-fed-test-pass id-fed-test-count)")
(epoch 110)
(eval "(list id-expiry-test-pass id-expiry-test-count)")
(epoch 111)
(eval "(list id-clients-test-pass id-clients-test-count)")
(epoch 112)
(eval "(list id-grants-test-pass id-grants-test-count)")
(epoch 113)
(eval "(list id-device-test-pass id-device-test-count)")
(epoch 114)
(eval "(list id-facade-test-pass id-facade-test-count)")
(epoch 115)
(eval "(list id-deleg-test-pass id-deleg-test-count)")
(epoch 116)
(eval "(list id-smgmt-test-pass id-smgmt-test-count)")
(epoch 117)
(eval "(list id-xchg-test-pass id-xchg-test-count)")
(epoch 118)
(eval "(list id-intr-test-pass id-intr-test-count)")
(epoch 119)
(eval "(list id-par-test-pass id-par-test-count)")
(epoch 120)
(eval "(list id-dyn-test-pass id-dyn-test-count)")
(epoch 121)
(eval "(list id-acct-test-pass id-acct-test-count)")
(epoch 122)
(eval "(list id-pkce-test-pass id-pkce-test-count)")
EPOCHS

timeout 1200 "$SX_SERVER" < "$TMPFILE" > "$OUTFILE" 2>&1

parse_pair() {
  local epoch="$1"
  local line
  line=$(grep -A1 "^(ok-len $epoch " "$OUTFILE" | tail -1)
  echo "$line" | sed -E 's/[()]//g'
}

TOTAL_PASS=0
TOTAL_COUNT=0
JSON_SUITES=""
MD_ROWS=""

idx=0
for entry in "${SUITES[@]}"; do
  name="${entry%%|*}"
  epoch=$((100 + idx))
  pair=$(parse_pair "$epoch")
  pass=$(echo "$pair" | awk '{print $1}')
  count=$(echo "$pair" | awk '{print $2}')
  if [ -z "$pass" ] || [ -z "$count" ]; then
    pass=0
    count=0
  fi
  TOTAL_PASS=$((TOTAL_PASS + pass))
  TOTAL_COUNT=$((TOTAL_COUNT + count))
  status="ok"
  marker="✅"
  if [ "$pass" != "$count" ]; then
    status="fail"
    marker="❌"
  fi
  if [ "$VERBOSE" = "-v" ]; then
    printf "  %-12s %s/%s\n" "$name" "$pass" "$count"
  fi
  if [ -n "$JSON_SUITES" ]; then JSON_SUITES+=","; fi
  JSON_SUITES+=$'\n    '
  JSON_SUITES+="{\"name\":\"$name\",\"pass\":$pass,\"total\":$count,\"status\":\"$status\"}"
  MD_ROWS+="| $marker | $name | $pass | $count |"$'\n'
  idx=$((idx + 1))
done

printf '\nidentity-on-sx conformance: %d / %d\n' "$TOTAL_PASS" "$TOTAL_COUNT"

cat > lib/identity/scoreboard.json <<JSON
{
  "language": "identity",
  "total_pass": $TOTAL_PASS,
  "total": $TOTAL_COUNT,
  "suites": [$JSON_SUITES
  ]
}
JSON

cat > lib/identity/scoreboard.md <<MD
# identity-on-sx Scoreboard

**Total: ${TOTAL_PASS} / ${TOTAL_COUNT} tests passing**

|  | Suite | Pass | Total |
|---|---|---|---|
$MD_ROWS

Generated by \`lib/identity/conformance.sh\`.
MD

if [ "$TOTAL_PASS" -eq "$TOTAL_COUNT" ]; then
  exit 0
else
  exit 1
fi
