#!/usr/bin/env bash
# API 文档漂移检测（#259 B1）：扫描 staged 的 controller.ts 文件，检查每个 HTTP
# 装饰器对应的路径是否在 docs/modules/{module}/07-api.md 里出现。
#
# 为什么有这个：盘点报告（testing/reports/ai-review-stats-20260511.md）显示
# "contract 文档漂移"是 AI Review 高频 risk finding（PR #247 五次 review 都
# 包含 "07-api.md 缺端点" 类报告）。把这类问题从 PR 阶段左移到 pre-commit，
# 0 AI 成本、确定性高、立刻见效。
#
# 当前阶段：warn-only（观察期）。data 稳定后切到 --mode block。
#
# 用法：
#   bash scripts/ops/check-api-doc-drift.sh              # 默认 warn 模式
#   bash scripts/ops/check-api-doc-drift.sh --mode block # 失败时 exit 1
#
# 已知简化（接受的取舍）：
#   - controller prefix 用首个 @Controller('xxx') 匹配，不解析多 @Controller 同文件
#   - 路径参数 :id / {id} 都尝试匹配（07-api.md 写法可能不一致）
#   - 不展开 `${variable}` 或常量引用的路径（极少见）

set -euo pipefail

MODE="warn"
while [[ $# -gt 0 ]]; do
  case "$1" in
    --mode) MODE="$2"; shift 2 ;;
    -h|--help) sed -n '2,18p' "$0" | sed 's/^# \?//'; exit 0 ;;
    *) echo "未知参数: $1" >&2; exit 2 ;;
  esac
done

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$ROOT_DIR"

STAGED=$(git diff --cached --name-only --diff-filter=AM -- 'backend/src/**/*.controller.ts' 2>/dev/null || true)
if [ -z "$STAGED" ]; then
  exit 0
fi

declare -a MISSING=()
declare -a CHECKED=()

for f in $STAGED; do
  [ -f "$f" ] || continue

  # 取 controller 路径前缀（首个 @Controller('xxx')）
  CONTROLLER_PATH=$(grep -oE "@Controller\(['\"][^'\"]*['\"]" "$f" | head -1 \
    | sed -E "s/@Controller\(['\"]([^'\"]*)['\"]?/\1/" || true)

  # 推断模块名 — 假设 backend/src/<root>/<module>/.../foo.controller.ts
  # 优先级 1：路径含 "/modules/<x>/" → 取 <x> 作模块（兼容 modules/agent/controllers/...,
  #          modules/robot-manager/l3-business/..., modules/robot-manager/admin/... 等任意子树）
  # 优先级 2：fallback 老启发式（NF-1，处理 backend/src/engines/form/<module>/ 这类）
  MODULE=$(echo "$f" | awk -F/ '{
    for (i = 1; i <= NF; i++) {
      if ($i == "modules" && i < NF) { print $(i+1); exit }
    }
    if (NF >= 4) {
      if ($(NF-1) == "controllers" && NF >= 5) print $(NF-2);
      else print $(NF-1);
    } else print ""
  }')
  if [ -z "$MODULE" ]; then
    continue
  fi

  # 容许多种文档位置（部分模块嵌套在更深路径）
  # 嵌套模块（如 backend/src/modules/organization/auth/.../*.controller.ts）：NF-1
  # 推断出来的是子模块（auth），但实际文档在父模块下（organization/07-api.md）
  PARENT_MODULE=$(echo "$f" | awk -F/ '{ if (NF >= 5) print $(NF-2); else print "" }')
  DOC=""
  for candidate in \
      "docs/modules/$MODULE/07-api.md" \
      "docs/modules/${MODULE%-controller}/07-api.md" \
      "docs/modules/$PARENT_MODULE/07-api.md"; do
    if [ -n "$candidate" ] && [ -f "$candidate" ]; then DOC="$candidate"; break; fi
  done

  # 提取所有 HTTP 装饰器及行号
  while IFS=: read -r LINE_NUM CONTENT; do
    METHOD_PATH=$(echo "$CONTENT" \
      | sed -nE "s/.*@(Get|Post|Put|Patch|Delete)\(['\"]([^'\"]*)['\"].*/\2/p" \
      | head -1)
    # @Get() 不带 path → 走 controller prefix
    FULL=""
    if [ -n "$CONTROLLER_PATH" ] && [ -n "$METHOD_PATH" ]; then
      FULL="${CONTROLLER_PATH}/${METHOD_PATH}"
    elif [ -n "$CONTROLLER_PATH" ]; then
      FULL="${CONTROLLER_PATH}"
    elif [ -n "$METHOD_PATH" ]; then
      FULL="${METHOD_PATH}"
    fi
    FULL="${FULL%/}"  # 去尾 /
    [ -z "$FULL" ] && continue

    CHECKED+=("$f:$LINE_NUM → $FULL")

    if [ -z "$DOC" ]; then
      MISSING+=("$f:$LINE_NUM → /$FULL → 模块 $MODULE 无对应 07-api.md")
      continue
    fi
    # :id / {id} 两种写法都允许匹配。
    # 同时允许文档用"模块相对路径"（07-api.md 通常在顶部声明 "Base URL: /api/v1/{module}"，
    # 正文表格/section 标题只写相对路径如 `/users/:id`，不带 module 前缀）→ PATTERN3 剥掉
    # module 前缀再匹配一次。不加这道 fallback 会把 70+ 完整文档化的 endpoint 全报成 missing。
    PATTERN1="$FULL"
    PATTERN2=$(echo "$FULL" | sed -E 's/:([a-zA-Z_][a-zA-Z0-9_]*)/{\1}/g')
    PATTERN3="${FULL#$MODULE}"
    PATTERN4=$(echo "$PATTERN3" | sed -E 's/:([a-zA-Z_][a-zA-Z0-9_]*)/{\1}/g')
    if ! grep -qF -- "$PATTERN1" "$DOC" \
       && ! grep -qF -- "$PATTERN2" "$DOC" \
       && ! grep -qF -- "$PATTERN3" "$DOC" \
       && ! grep -qF -- "$PATTERN4" "$DOC"; then
      MISSING+=("$f:$LINE_NUM → /$FULL → 缺 in $DOC")
    fi
  done < <(grep -nE "^[[:space:]]*@(Get|Post|Put|Patch|Delete)\(" "$f" || true)
done

if [ ${#MISSING[@]} -eq 0 ]; then
  if [ ${#CHECKED[@]} -gt 0 ]; then
    echo "✓ API-doc drift check: ${#CHECKED[@]} 个端点全部在 07-api.md 中" >&2
  fi
  exit 0
fi

echo "" >&2
echo "⚠️  API-doc drift: ${#MISSING[@]} 个端点未在对应 07-api.md 中记录" >&2
for m in "${MISSING[@]}"; do
  echo "  - $m" >&2
done
echo "" >&2
echo "解决：在对应 docs/modules/{module}/07-api.md 补 endpoint 章节" >&2
echo "  - 写法：路径 + method + 请求/响应 schema（参考同模块已有端点）" >&2
echo "  - 或运行 @docs-main skill 让 AI 补 doc 草稿" >&2

if [ "$MODE" = "block" ]; then
  exit 1
fi
echo "" >&2
echo "（当前 mode=warn，不阻断 commit；后续数据稳定后会切到 --mode block）" >&2
exit 0
