#!/usr/bin/env sh

set -eu

MODE="detach"
CODE_TIMEOUT="30"
WAIT_TIMEOUT="600"
RUN_DIR="${TMPDIR:-/tmp}/dws-device-login"

usage() {
  cat <<'USAGE'
用法:
  ./scripts/device-login-dws.sh [--detach|--wait] [--code-timeout 秒] [--wait-timeout 秒]

用途:
  在无图形界面/远程/Codex 同步执行环境中启动 dws 设备授权登录。
  脚本会把 `dws auth login --device` 放到后台，先从日志中提取授权链接和授权码，
  再在授权命令仍在轮询时展示出来，避免“命令结束后才看到旧码”的死锁。

选项:
  --detach          默认。打印授权链接、授权码、PID 和日志路径后立即返回，后台登录继续轮询。
  --wait            打印授权链接和授权码后继续等待后台命令结束，适合普通交互式终端。
  --code-timeout N  等待授权链接和授权码出现在日志中的秒数，默认 30。
  --wait-timeout N  --wait 模式下等待授权完成的秒数，默认 600。
  -h, --help        显示帮助。
USAGE
}

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

is_number() {
  case "$1" in
    ''|*[!0-9]*) return 1 ;;
    *) return 0 ;;
  esac
}

while [ "$#" -gt 0 ]; do
  case "$1" in
    --detach)
      MODE="detach"
      ;;
    --wait)
      MODE="wait"
      ;;
    --code-timeout)
      shift
      [ "$#" -gt 0 ] || fail "--code-timeout 需要秒数" 2
      is_number "$1" || fail "--code-timeout 必须是数字" 2
      CODE_TIMEOUT="$1"
      ;;
    --wait-timeout)
      shift
      [ "$#" -gt 0 ] || fail "--wait-timeout 需要秒数" 2
      is_number "$1" || fail "--wait-timeout 必须是数字" 2
      WAIT_TIMEOUT="$1"
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      fail "未知参数: $1" 2
      ;;
  esac
  shift
done

command -v dws >/dev/null 2>&1 || fail "未找到 dws，请先安装 dingtalk-workspace-cli" 10
command -v grep >/dev/null 2>&1 || fail "缺少 grep，无法提取授权链接和授权码" 11

mkdir -p "${RUN_DIR}"
STAMP="$(date +%Y%m%d-%H%M%S 2>/dev/null || echo now)-$$"
LOG_FILE="${RUN_DIR}/device-login-${STAMP}.log"
STATUS_FILE="${RUN_DIR}/device-login-${STAMP}.status"
PID_FILE="${RUN_DIR}/device-login-${STAMP}.pid"

# 使用 nohup + 子 shell 脱离当前同步执行管道；父进程返回后，dws 仍继续轮询当前授权码。
nohup sh -c 'NO_COLOR=1 dws auth login --device >"$1" 2>&1; code=$?; printf "%s\n" "$code" >"$2"' sh "${LOG_FILE}" "${STATUS_FILE}" >/dev/null 2>&1 &
LOGIN_PID="$!"
printf '%s\n' "${LOGIN_PID}" >"${PID_FILE}"

AUTH_URL=""
CODE=""
elapsed=0
while [ "${elapsed}" -lt "${CODE_TIMEOUT}" ]; do
  if [ -s "${LOG_FILE}" ]; then
    AUTH_URL="$(grep -Eo 'https?://[^[:space:]]+' "${LOG_FILE}" | head -n 1 || true)"
    CODE="$(grep -Eo '[A-Z0-9]{4}-[A-Z0-9]{4}' "${LOG_FILE}" | head -n 1 || true)"
    [ -n "${AUTH_URL}" ] && [ -n "${CODE}" ] && break
  fi

  if [ -s "${STATUS_FILE}" ]; then
    break
  fi

  sleep 1
  elapsed=$((elapsed + 1))
done

if [ -n "${CODE}" ]; then
  echo "[OK] 设备授权登录已在后台轮询"
  if [ -n "${AUTH_URL}" ]; then
    echo "授权链接: ${AUTH_URL}"
  else
    echo "[WARN] 未在日志中识别到授权链接，请查看日志中的原始登录提示。"
  fi
  echo "授权码: ${CODE}"
  echo "请立即打开授权链接，在钉钉/浏览器授权页面输入或扫码确认该授权码；不要重新运行 dws auth login --device。"
else
  echo "[WARN] ${CODE_TIMEOUT}s 内未在日志中识别到授权码"
  echo "请查看日志中的原始登录提示；不要反复重启登录命令，除非后台进程已结束。"
fi

echo "后台 PID: ${LOGIN_PID}"
echo "日志文件: ${LOG_FILE}"
echo "状态文件: ${STATUS_FILE}"
echo "检查登录态: dws auth status --format json"
echo "查看日志: tail -f ${LOG_FILE}"

if [ "${MODE}" = "detach" ]; then
  exit 0
fi

echo
if [ -n "${CODE}" ]; then
  echo "[wait] 已展示授权链接和授权码，继续等待授权完成，最长 ${WAIT_TIMEOUT}s ..."
else
  echo "[wait] 继续等待后台命令结束，最长 ${WAIT_TIMEOUT}s ..."
fi

elapsed=0
while [ "${elapsed}" -lt "${WAIT_TIMEOUT}" ]; do
  if [ -s "${STATUS_FILE}" ]; then
    code="$(cat "${STATUS_FILE}" 2>/dev/null || echo 1)"
    if [ "${code}" = "0" ]; then
      echo "[OK] dws 设备授权登录完成"
      dws auth status --format json || true
      exit 0
    fi
    echo "[FAIL] dws 设备授权登录命令已退出，状态码: ${code}" >&2
    echo "最近日志:" >&2
    tail -n 20 "${LOG_FILE}" >&2 || true
    exit "${code}"
  fi
  sleep 1
  elapsed=$((elapsed + 1))
done

echo "[WARN] 等待授权超时，但后台进程可能仍在轮询；请检查日志和登录态。" >&2
echo "日志文件: ${LOG_FILE}" >&2
exit 124
