#!/usr/bin/env bash
# phase5_usage.sh — usage 统计端点真实环境 e2e 验收（plan §5.3，P5-T2 的补充）。
#
# 覆盖 GET /api/v1/agent/api-keys/:id/usage：
#   ① 先用 agent key 真实调用 N 次 /caasm/assets，再查 usage → code 0
#     且 total_calls>=N、daily_counts 含今日且 count>=N、resource_breakdown 含 caasm、
#     last_used_at 非空、window_days=30（默认窗口）
#   ② days=7 → code 0 且 window_days=7
#   ③ days=15 → body code 400（非法窗口）
#   ④ 非数字 id → 400；不存在的 id → 404
#   ⑤ 他人（USER_B_TOKEN）查 A 的 key usage → 404（owner 隔离；不提供则跳过）
#
# 响应约定：response.Error 恒 HTTP 200 + body code，断言按 body code。
#
# 环境变量：
#   BASE_URL          后端地址，默认 http://127.0.0.1:8080
#   USER_TOKEN        造 key 用户的 access_token（需 agent:manage_own_keys + caasm:view_assets）【必填】
#   USER_B_TOKEN      另一用户的 access_token（用于 ⑤ 隔离用例；不提供则跳过）
#   CALLS             备料调用次数，默认 7（注意别超过 server 的 agent.default_quota_rpm）
#   EXPIRES_IN_HOURS  验收 key 的过期时长（小时），默认 1
#
# 依赖：bash、curl；jq 可选（无 jq 用 grep 兜底）。
set -euo pipefail

BASE_URL="${BASE_URL:-http://127.0.0.1:8080}"
USER_TOKEN="${USER_TOKEN:-}"
USER_B_TOKEN="${USER_B_TOKEN:-}"
CALLS="${CALLS:-7}"
EXPIRES_IN_HOURS="${EXPIRES_IN_HOURS:-1}"

PASS_COUNT=0
FAIL_COUNT=0

log()  { printf '[phase5-e2e] %s\n' "$*"; }
pass() { PASS_COUNT=$((PASS_COUNT + 1)); printf '  [PASS] %s\n' "$*"; }
fail() { FAIL_COUNT=$((FAIL_COUNT + 1)); printf '  [FAIL] %s\n' "$*" >&2; }

# ---------------------------------------------------------------------------
# HTTP 断言（一律按 body code，不断言 HTTP 状态码）
# ---------------------------------------------------------------------------
http_call() { # method path [header|--curl-opt value]... → stdout = response body
  local method="$1" path="$2"
  shift 2
  local args=(-sS --max-time 10 -X "$method")
  while [[ $# -gt 0 ]]; do
    case "$1" in
      --*) args+=("$1" "$2"); shift 2 ;;
      *)   args+=(-H "$1"); shift ;;
    esac
  done
  curl "${args[@]}" "${BASE_URL}${path}"
}

body_code() {
  local body="$1"
  if command -v jq >/dev/null 2>&1; then
    jq -r '.code // empty' <<<"$body"
  else
    grep -o '"code":[0-9-]*' <<<"$body" | head -1 | cut -d: -f2
  fi
}

body_data_field() { # body field → .data.<field> 字符串值
  local body="$1" field="$2"
  if command -v jq >/dev/null 2>&1; then
    jq -r ".data.${field} // empty" <<<"$body"
  else
    grep -o "\"${field}\":\"[^\"]*\"" <<<"$body" | head -1 | sed "s/\"${field}\":\"//; s/\"\$//"
  fi
}

assert_body_code() { # name body want_code
  local name="$1" body="$2" want_code="$3" code
  code="$(body_code "$body")"
  if [[ "$code" != "$want_code" ]]; then
    fail "${name}: body code=${code:-<无code字段>}, 期望 ${want_code}; body=$(head -c 300 <<<"$body")"
    return 1
  fi
  pass "${name}: body code=${code}"
}

expires_at_iso() {
  if date -u -v+1H +%Y-%m-%dT%H:%M:%SZ >/dev/null 2>&1; then
    date -u -v+"${EXPIRES_IN_HOURS}"H +%Y-%m-%dT%H:%M:%SZ
  else
    date -u -d "+${EXPIRES_IN_HOURS} hours" +%Y-%m-%dT%H:%M:%SZ
  fi
}

preflight() {
  local missing=()
  command -v curl >/dev/null 2>&1 || missing+=("curl")
  [[ -n "$USER_TOKEN" ]] || missing+=("USER_TOKEN 未提供（造 key 用户的 access_token）")
  [[ "$CALLS" =~ ^[0-9]+$ ]] && ((CALLS >= 1)) || missing+=("CALLS 必须为正整数")
  if ((${#missing[@]} > 0)); then
    printf '  [FAIL] preflight:\n' >&2
    printf '    - %s\n' "${missing[@]}" >&2
    exit 1
  fi
}

main() {
  preflight

  # 备料：创建 key
  local body key_id plaintext
  body="$(http_call POST /api/v1/agent/api-keys \
    "Authorization: Bearer ${USER_TOKEN}" "Content-Type: application/json" \
    --data-raw "{\"agent_name\":\"e2e-phase5-usage\",\"permission_scope\":[\"caasm:view_assets\"],\"expires_at\":\"$(expires_at_iso)\"}")"
  assert_body_code "备料: 创建验收 key" "$body" 0 || { log "创建失败, 无法继续"; exit 1; }
  key_id="$(body_data_field "$body" id)"
  plaintext="$(body_data_field "$body" api_key)"
  [[ -n "$key_id" && -n "$plaintext" ]] || { log "创建响应缺 id/api_key, 无法继续; body=${body}"; exit 1; }

  # 备料：用该 key 真实调用 CALLS 次（产生审计记录）
  local i code
  for ((i = 1; i <= CALLS; i++)); do
    code="$(body_code "$(http_call GET /api/v1/caasm/assets "X-API-Key: ${plaintext}")")"
    if [[ "$code" != "0" ]]; then
      log "备料第 ${i} 次调用 code=${code}（配额?）, 无法继续"; exit 1
    fi
  done
  pass "备料: 用验收 key 调用 ${CALLS} 次 /caasm/assets 全部放行"

  # ① usage 聚合正确性
  body="$(http_call GET "/api/v1/agent/api-keys/${key_id}/usage" "Authorization: Bearer ${USER_TOKEN}")"
  assert_body_code "① 查询 usage" "$body" 0 || { log "usage 查询失败, 无法继续"; exit 1; }

  local total window today_cnt
  total="$(body_data_field "$body" total_calls)"
  window="$(body_data_field "$body" window_days)"
  if [[ "$total" =~ ^[0-9]+$ ]] && ((total >= CALLS)); then
    pass "① total_calls=${total} >= ${CALLS}"
  else
    fail "① total_calls=${total}, 期望 >= ${CALLS}; body=$(head -c 300 <<<"$body")"
  fi
  [[ "$window" == "30" ]] && pass "① 默认窗口 window_days=30" || fail "① window_days=${window}, 期望 30"

  local today; today="$(date -u +%Y-%m-%d)"
  if command -v jq >/dev/null 2>&1; then
    today_cnt="$(jq -r --arg d "$today" '[.data.daily_counts[]? | select(.date==$d) | .count] | first // 0' <<<"$body")"
  else
    today_cnt="$(grep -o "\"date\":\"${today}\",\"count\":[0-9]*" <<<"$body" | head -1 | cut -d: -f3)"
  fi
  if [[ "$today_cnt" =~ ^[0-9]+$ ]] && ((today_cnt >= CALLS)); then
    pass "① daily_counts 含今日(${today}) count=${today_cnt} >= ${CALLS}"
  else
    fail "① daily_counts 今日 count=${today_cnt:-缺失}, 期望 >= ${CALLS}; body=$(head -c 400 <<<"$body")"
  fi

  if grep -q '"resource_type":"caasm"' <<<"$body"; then
    pass "① resource_breakdown 含 caasm"
  else
    fail "① resource_breakdown 缺 caasm; body=$(head -c 400 <<<"$body")"
  fi
  if grep -q '"last_used_at":"' <<<"$body"; then
    pass "① last_used_at 非空"
  else
    fail "① last_used_at 为空; body=$(head -c 300 <<<"$body")"
  fi

  # ② days=7
  body="$(http_call GET "/api/v1/agent/api-keys/${key_id}/usage?days=7" "Authorization: Bearer ${USER_TOKEN}")"
  assert_body_code "② days=7 查询" "$body" 0
  window="$(body_data_field "$body" window_days)"
  [[ "$window" == "7" ]] && pass "② window_days=7" || fail "② window_days=${window}, 期望 7"

  # ③ 非法窗口
  body="$(http_call GET "/api/v1/agent/api-keys/${key_id}/usage?days=15" "Authorization: Bearer ${USER_TOKEN}")"
  assert_body_code "③ days=15 非法窗口 → 400" "$body" 400

  # ④ 非法/不存在 id
  body="$(http_call GET "/api/v1/agent/api-keys/abc/usage" "Authorization: Bearer ${USER_TOKEN}")"
  assert_body_code "④ 非数字 id → 400" "$body" 400
  body="$(http_call GET "/api/v1/agent/api-keys/99999999/usage" "Authorization: Bearer ${USER_TOKEN}")"
  assert_body_code "④ 不存在的 id → 404" "$body" 404

  # ⑤ 他人查 usage → 404（owner 隔离）
  if [[ -n "$USER_B_TOKEN" ]]; then
    body="$(http_call GET "/api/v1/agent/api-keys/${key_id}/usage" "Authorization: Bearer ${USER_B_TOKEN}")"
    assert_body_code "⑤ B 查 A 的 key usage → 404（隔离）" "$body" 404
  else
    log "  [SKIP] ⑤ 未提供 USER_B_TOKEN, 跳过隔离用例"
  fi

  log "结果: PASS=${PASS_COUNT}, FAIL=${FAIL_COUNT}"
  ((FAIL_COUNT == 0)) || exit 1
  log "usage 端点真实环境验收全部通过"
}

main "$@"
