#!/usr/bin/env bash
# 实机验证辅助：读取界面文字 / 按文字点击 / 截图 / 抓请求体。
#
# 为什么需要它：手机端验证要反复点 Tab、弹层按钮、卡片链接。靠肉眼估坐标点击
# 极易点空（本次适配就因此白跑了几轮），而 uiautomator 能拿到元素真实 bounds。
# tap-text 直接按文字定位并点中心，比手算坐标可靠得多。
#
# 用法：
#   ui_probe.sh <serial> texts                  列出当前界面所有可见文字
#   ui_probe.sh <serial> bounds "已交接"         打印该文字元素的 bounds 与中心点
#   ui_probe.sh <serial> tap-text "确认" [序号]   按文字点击（取中心点）；同名多处时默认第 1 处
#   ui_probe.sh <serial> wait-text "待交接" [秒] 等文字出现（默认 20 秒），点击前先等页面就绪
#   ui_probe.sh <serial> wait-gone "请稍候……" [秒] 等文字消失（如等加载弹窗关闭）
#   ui_probe.sh <serial> shot /tmp/a.png        截图到本地
#   ui_probe.sh <serial> req <关键字>            从 logcat 抓含关键字的请求/响应体
#   ui_probe.sh <serial> crash                  统计并打印最近一次崩溃栈
#   ui_probe.sh <serial> form                   打印形态识别结果 PHONE/TABLET

set -uo pipefail

SERIAL="${1:?用法: ui_probe.sh <serial> <命令> [参数]}"
CMD="${2:?缺少命令}"
ARG="${3:-}"
PKG="com.lukouguoji.aerologic"
A="adb -s $SERIAL"

dump() {
  $A shell uiautomator dump /sdcard/_probe.xml >/dev/null 2>&1
  # 注意：dump 出来的 XML 是一整行，必须按 '<' 拆成一节点一行才能按节点过滤。
  # （`tr '>' '>\n'` 是字符映射不是字符串替换，等于空操作，别踩这个坑。）
  $A shell cat /sdcard/_probe.xml | tr '<' '\n'
}

# 打印所有 text 完全等于 $1 的节点的 bounds 与中心点
centers_of() {
  dump | grep -F "text=\"$1\"" \
    | grep -oE 'bounds="\[[0-9]+,[0-9]+\]\[[0-9]+,[0-9]+\]"' \
    | sed -E 's/bounds="\[([0-9]+),([0-9]+)\]\[([0-9]+),([0-9]+)\]"/\1 \2 \3 \4/' \
    | awk '{printf "bounds=[%d,%d][%d,%d] center=%d,%d\n", $1,$2,$3,$4, ($1+$3)/2, ($2+$4)/2}'
}

case "$CMD" in
  texts)
    dump | tr '<' '\n' | grep -oE 'text="[^"]+"' | sed 's/text=//;s/"//g' | awk '!seen[$0]++'
    ;;

  bounds)
    [ -z "$ARG" ] && { echo "需要文字参数"; exit 1; }
    centers_of "$ARG"
    ;;

  tap-text)
    [ -z "$ARG" ] && { echo "需要文字参数"; exit 1; }
    idx="${4:-1}"
    all=$(centers_of "$ARG")
    [ -z "$all" ] && { echo "界面上找不到文字：$ARG"; exit 1; }
    total=$(echo "$all" | wc -l | tr -d ' ')
    # 同一文字可能在多处出现（如底部 Tab「国际」与列表里的「国际」），
    # 默认点第 1 个；命中多个时提示，必要时用第 4 个参数指定序号。
    if [ "$total" -gt 1 ]; then
      echo "注意：${ARG} 命中 $total 处，正在点第 $idx 处（可用第 4 个参数指定序号）"
      echo "$all" | nl -w2 -s'  '
    fi
    line=$(echo "$all" | sed -n "${idx}p")
    [ -z "$line" ] && { echo "序号 $idx 超出范围（共 $total 处）"; exit 1; }
    cx=${line#*center=}; cx=${cx%%,*}
    cy=${line##*,}
    # 变量必须写成 ${ARG}：紧跟中文标点时 $ARG 会被当成变量名的一部分
    echo "tap ${ARG} @ $cx,$cy"
    $A shell input tap "$cx" "$cy"
    ;;

  # 等某段文字出现 / 消失。点击前先等页面就绪很重要：
  # 加载弹窗（"请稍候……"）会盖住整屏并吞掉 input tap，导致点击"静默失效"。
  wait-text)
    [ -z "$ARG" ] && { echo "需要文字参数"; exit 1; }
    for _ in $(seq 1 "${4:-20}"); do
      if dump | grep -qF "text=\"$ARG\""; then echo "出现: ${ARG}"; exit 0; fi
      sleep 1
    done
    echo "超时未出现: ${ARG}"; exit 1
    ;;

  wait-gone)
    [ -z "$ARG" ] && { echo "需要文字参数"; exit 1; }
    for _ in $(seq 1 "${4:-20}"); do
      if ! dump | grep -qF "text=\"$ARG\""; then echo "已消失: ${ARG}"; exit 0; fi
      sleep 1
    done
    echo "超时仍存在: ${ARG}"; exit 1
    ;;

  shot)
    out="${ARG:-/tmp/shot.png}"
    $A exec-out screencap -p > "$out"
    echo "$out ($(wc -c < "$out") bytes)"
    ;;

  req)
    # OkHttp 日志是多行 pretty JSON，用 -v raw 拿干净文本再按关键字取上下文
    $A logcat -d -v raw | grep -B24 -A24 -- "${ARG:-POST}" | grep -E '^\s*"|POST|<-- [0-9]{3}' | tail -60
    ;;

  crash)
    n=$($A logcat -d | grep -c "FATAL EXCEPTION" || true)
    echo "FATAL EXCEPTION 次数: $n"
    if [ "$n" -gt 0 ]; then
      $A logcat -d | grep -A25 "FATAL EXCEPTION" | tail -30
    fi
    ;;

  form)
    $A logcat -d -s BaseActivity:D | grep -oE "(PHONE|TABLET)\(sw=[0-9]+dp[^)]*\)" | tail -3
    ;;

  *)
    echo "未知命令: $CMD"; exit 1
    ;;
esac
