#!/usr/bin/env bash
# verify-doc-impl.sh
#
# Doc-impl alignment grep, promoted from the manual verification step
# to a permanent gate. Run from anywhere; resolves to the plugin tree itself.
#
# Verifies:
#   1. Every `outlook-*` tool name in `platform/plugins/docs/references/outlook-guide.md`
#      resolves to a `server.tool("outlook-...", ...)` registration in mcp/src/index.ts.
#   2. Every `[outlook-mcp]` log-line shape in outlook-guide.md matches a
#      log({event:"..."}) literal in mcp/src/.
#   3. Every tool name in `PLUGIN.md` frontmatter matches a registration in mcp/src/index.ts.
#   4. Public-agent isolation: `outlook` does not appear in public-agent assembly files.
#   5. Bearer-token redaction: log.ts contains the redaction regex pair.
#
# Exit non-zero on any mismatch. Print the first diverging item.

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PLUGIN_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
REPO_ROOT="$(cd "$PLUGIN_DIR/../../../.." && pwd)"
GUIDE="$REPO_ROOT/platform/plugins/docs/references/outlook-guide.md"
PLUGIN_MD="$REPO_ROOT/platform/plugins/outlook/PLUGIN.md"
INDEX_TS="$PLUGIN_DIR/src/index.ts"
SRC_DIR="$PLUGIN_DIR/src"

fail() {
  echo "[verify-doc-impl] FAIL: $1" >&2
  exit 1
}

[ -f "$GUIDE" ] || fail "operator guide missing: $GUIDE"
[ -f "$PLUGIN_MD" ] || fail "PLUGIN.md missing: $PLUGIN_MD"
[ -f "$INDEX_TS" ] || fail "index.ts missing: $INDEX_TS"

# Tool names registered in src/index.ts. The MCP-SDK call shape is:
#   server.tool(
#     "outlook-XYZ",
#     ...
# so the tool name appears on its own line as `  "outlook-XYZ",`.
TOOLS_REGISTERED=$(grep -oE '"outlook-[a-z\-]+",' "$INDEX_TS" \
  | sed -E 's/^"|",$//g' | sort -u)

# Tool names referenced in outlook-guide.md (backtick-wrapped)
TOOLS_IN_GUIDE=$(grep -oE '`outlook-[a-z\-]+`' "$GUIDE" | tr -d '`' | sort -u)

# Tool names in PLUGIN.md frontmatter (lines shaped "  - name: outlook-...")
TOOLS_IN_PLUGIN_MD=$(grep -E '^[[:space:]]+- name: outlook-' "$PLUGIN_MD" | sed -E 's/^[[:space:]]*-[[:space:]]+name:[[:space:]]*//' | sort -u)

# Set 1: every tool in guide must be registered
while IFS= read -r tool; do
  [ -z "$tool" ] && continue
  if ! echo "$TOOLS_REGISTERED" | grep -qx "$tool"; then
    fail "tool '$tool' referenced in outlook-guide.md but not registered in mcp/src/index.ts"
  fi
done <<< "$TOOLS_IN_GUIDE"

# Set 2: every tool in PLUGIN.md frontmatter must be registered
while IFS= read -r tool; do
  [ -z "$tool" ] && continue
  if ! echo "$TOOLS_REGISTERED" | grep -qx "$tool"; then
    fail "tool '$tool' declared in PLUGIN.md frontmatter but not registered in mcp/src/index.ts"
  fi
done <<< "$TOOLS_IN_PLUGIN_MD"

# Set 3: every registered tool must appear in PLUGIN.md frontmatter
while IFS= read -r tool; do
  [ -z "$tool" ] && continue
  if ! echo "$TOOLS_IN_PLUGIN_MD" | grep -qx "$tool"; then
    fail "tool '$tool' registered in mcp/src/index.ts but missing from PLUGIN.md frontmatter"
  fi
done <<< "$TOOLS_REGISTERED"

# Log-shape alignment: every event tag in outlook-guide.md must have a matching
# log({ event: "..." }) literal in mcp/src/. Event tags appear in the table as:
#   | Auth init | `auth-init account=<id> codeChallenge=...` |
# We pull the first word inside backticks on each table row that contains "account=".
EVENTS_IN_GUIDE=$(grep -E '`[a-z\-]+ account=' "$GUIDE" \
  | sed -E 's/.*`([a-z\-]+) account=.*/\1/' | sort -u)
EVENTS_IN_SRC=$(grep -rh -oE 'event:[[:space:]]*"[a-z\-]+"' "$SRC_DIR" \
  | sed -E 's/^event:[[:space:]]*"|"$//g' | sort -u)

while IFS= read -r ev; do
  [ -z "$ev" ] && continue
  if ! echo "$EVENTS_IN_SRC" | grep -qx "$ev"; then
    fail "log event '$ev' documented in outlook-guide.md but no log({event:\"$ev\"}) literal in mcp/src/"
  fi
done <<< "$EVENTS_IN_GUIDE"

# Public-agent isolation: outlook must not appear in public-agent assembly files.
ISOLATION_HITS=$( (cd "$REPO_ROOT" && grep -rE 'outlook' \
  platform/ui/app/lib/claude-agent/public-agent.ts \
  platform/ui/app/lib/claude-agent/system-prompt-assembly.ts \
  platform/templates/agents/public/ 2>/dev/null) || true)
if [ -n "$ISOLATION_HITS" ]; then
  echo "$ISOLATION_HITS" >&2
  fail "isolation breach: 'outlook' string appears in public-agent assembly path"
fi

# Bearer redaction guard: lib/log.ts must contain both regex literals.
if ! grep -q 'Bearer\\s+\[A-Za-z0-9' "$SRC_DIR/lib/log.ts"; then
  fail "Bearer redaction regex missing in lib/log.ts"
fi
if ! grep -q 'access_token=\[A-Za-z0-9' "$SRC_DIR/lib/log.ts"; then
  fail "access_token redaction regex missing in lib/log.ts"
fi

echo "[verify-doc-impl] OK — $(echo "$TOOLS_REGISTERED" | wc -l | tr -d ' ') tools, $(echo "$EVENTS_IN_GUIDE" | wc -l | tr -d ' ') events, isolation, redaction all aligned"
