#!/bin/bash
# ============================================================
# ZogToken Mac App 安装器 v1.4.0
#   生成一个真正的 ZogToken.app（原生登录页：输入 Group Key 点「连接」即知是否连上）
# 用法：
#   bash ZogToken-Installer.sh                 # 安装到 ~/Applications 并打开
#   bash ZogToken-Installer.sh --server=URL    # 指定平台地址
#   bash ZogToken-Installer.sh --print-plist   # 仅打印 Info.plist（自检用，不落盘）
#   bash ZogToken-Installer.sh --uninstall     # 卸载 App（保留设备令牌）
#   bash ZogToken-Installer.sh --purge         # 卸载 App 并清除本地令牌与常驻服务
# 兼容 macOS 13+ / bash 3.2；不写系统目录，不需要 sudo
# ============================================================
set -u
SERVER_DEFAULT="https://uwhats.com/zogtoken"
APP_NAME="ZogToken"
BUNDLE_ID="com.zogtoken.app"
APP_VER="1.4.0"
APPDIR="$HOME/Applications/$APP_NAME.app"
LABEL="com.zogtoken.agent"
PLIST="$HOME/Library/LaunchAgents/$LABEL.plist"
CONF="$HOME/.zogagent"

log() { printf "[zogtoken] %s\n" "$1"; }
usage() {
  cat <<'EOF'
ZogToken Mac App 安装器

  bash ZogToken-Installer.sh                 安装 ZogToken.app 到 ~/Applications 并打开
  bash ZogToken-Installer.sh --server=URL    指定平台地址（默认已内置）
  bash ZogToken-Installer.sh --print-plist   只打印 Info.plist
  bash ZogToken-Installer.sh --uninstall     卸载 App（保留设备令牌与常驻服务）
  bash ZogToken-Installer.sh --purge         卸载 App + 停止常驻服务 + 删除本地令牌
EOF
}

MODE="install"; SERVER="${ZOG_SERVER:-$SERVER_DEFAULT}"
for a in "$@"; do
  case "$a" in
    --install|--open) MODE="install" ;;
    --uninstall) MODE="uninstall" ;;
    --purge) MODE="purge" ;;
    --print-plist) MODE="plist" ;;
    --server=*) SERVER="${a#--server=}" ;;
    -h|--help) usage; exit 0 ;;
  esac
done
log "平台地址：$SERVER"

if ! command -v curl >/dev/null 2>&1; then log "缺少 curl，无法继续"; exit 1; fi

# ---------- Info.plist ----------
PLIST_CONTENT='<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>CFBundleName</key><string>ZogToken</string>
  <key>CFBundleDisplayName</key><string>ZogToken</string>
  <key>CFBundleIdentifier</key><string>com.zogtoken.app</string>
  <key>CFBundleVersion</key><string>1.4.0</string>
  <key>CFBundleShortVersionString</key><string>1.4.0</string>
  <key>CFBundleExecutable</key><string>ZogToken</string>
  <key>CFBundleIconFile</key><string>icon</string>
  <key>CFBundlePackageType</key><string>APPL</string>
  <key>CFBundleSignature</key><string>????</string>
  <key>CFBundleInfoDictionaryVersion</key><string>6.0</string>
  <key>LSMinimumSystemVersion</key><string>13.0</string>
  <key>NSHighResolutionCapable</key><true/>
  <key>LSUIElement</key><false/>
  <key>LSApplicationCategoryType</key><string>public.app-category.utilities</string>
</dict>
</plist>'

if [ "$MODE" = "plist" ]; then
  printf '%s\n' "$PLIST_CONTENT"
  exit 0
fi

if [ "$(uname -s)" != "Darwin" ]; then
  log "本安装器仅支持 macOS（当前系统：$(uname -s)）"
  exit 1
fi

# ---------- 卸载 ----------
stop_agent() {
  launchctl bootout "gui/$(id -u)/$LABEL" >/dev/null 2>&1
  launchctl unload -w "$PLIST" >/dev/null 2>&1
}
if [ "$MODE" = "uninstall" ] || [ "$MODE" = "purge" ]; then
  stop_agent
  rm -f "$PLIST"
  rm -rf "$APPDIR"
  if [ "$MODE" = "purge" ]; then
    rm -f "$CONF/device_token" "$CONF/register.json" "$CONF/hb.json" "$CONF/hb.err" "$CONF/task" \
          "$CONF/zogagent.log" "$CONF/zogagent.err.log" "$CONF/zogagent.sh"
    log "已卸载：App、常驻服务、本地设备令牌全部移除"
  else
    log "已卸载 App 与常驻服务（设备令牌保留在 ${CONF}）"
  fi
  exit 0
fi

# ---------- 生成 App ----------
log "正在生成 $APPDIR …"
mkdir -p "$APPDIR/Contents/MacOS" "$APPDIR/Contents/Resources"
printf '%s\n' "$PLIST_CONTENT" > "$APPDIR/Contents/Info.plist"

cat > "$APPDIR/Contents/MacOS/ZogToken" <<'APPMAIN'
#!/bin/bash
# ZogToken.app —— 登录（输入 Group Key）→ 连接 → 显示平台确认的连接状态
set -u
SERVER="https://uwhats.com/zogtoken"
CONF="$HOME/.zogagent"
TOKEN_FILE="$CONF/device_token"
AGENT_SH="$CONF/zogagent.sh"
LABEL="com.zogtoken.agent"
PLIST="$HOME/Library/LaunchAgents/$LABEL.plist"

# ---------- 原生对话框（所有文本走 argv，避免任何转义问题） ----------
ask_as() {   # msg, defaultText, btn1, btn2 → "按钮|输入内容"
  /usr/bin/osascript - "$@" <<'AS'
on run argv
  set r to display dialog (item 1 of argv) default answer (item 2 of argv) with title "ZogToken" buttons {item 3 of argv, item 4 of argv} default button (item 4 of argv)
  return (button returned of r) & "|" & (text returned of r)
end run
AS
}
alert_as() { # msg
  /usr/bin/osascript - "$@" <<'AS'
on run argv
  display dialog (item 1 of argv) with title "ZogToken" buttons {"好"} default button "好" with icon note
end run
AS
}
choice_as() { # msg, btn1, btn2, btn3 → 按钮名
  /usr/bin/osascript - "$@" <<'AS'
on run argv
  set r to display dialog (item 1 of argv) with title "ZogToken" buttons {item 2 of argv, item 3 of argv, item 4 of argv} default button (item 2 of argv)
  return button returned of r
end run
AS
}
notify_as() { # title, msg
  /usr/bin/osascript - "$@" <<'AS'
on run argv
  display notification (item 2 of argv) with title (item 1 of argv)
end run
AS
}

jget() { # $1=json $2=key  → 取字符串/数字/布尔
  printf '%s' "$1" | sed -n "s/.*\"$2\":\"\([^\"]*\)\".*/\1/p" | head -1
}
jbool() { # $1=json $2=key  → true/false
  case "$1" in *"\"$2\":true"*) echo "true" ;; *"\"$2\":false"*) echo "false" ;; *) echo "" ;; esac
}

agent_running() { launchctl list 2>/dev/null | grep -q "$LABEL"; }

platform_status() { # 用设备令牌向平台自查连接状态 → 打印多行文本
  local token json
  token=$(cat "$TOKEN_FILE" 2>/dev/null)
  if [ -z "$token" ]; then echo "本地没有设备令牌（尚未连接）"; return 1; fi
  json=$(curl -sS --max-time 12 -H "X-Device-Token: $token" "$SERVER/api/device/status?_t=$token" 2>&1)
  case "$json" in
    *'"ok":true'*) : ;;
    *'"ok":false'*|"") echo "平台未确认：$json"; return 1 ;;
  esac
  local name st grp ver task load
  name=$(jget "$json" name); st=$(jget "$json" status_zh); grp=$(jget "$json" group_key)
  task=$(jget "$json" task); load=$(jget "$json" load)
  ver=$(jbool "$json" verified)
  [ "$ver" = "true" ] && ver="已验证" || ver="待验证（让运维在控制台点「验证」放行）"
  printf '✅ 平台已确认连接\n\n设备：%s\n状态：%s\n验证：%s\n分组：%s\n用途：%s\n负载：%s\n服务端：%s\n' \
    "$name" "$st" "$ver" "$grp" "${task:-（未标注）}" "${load:-—}" "$SERVER"
  if [ "$st" = "离线" ]; then printf '\n提示：刚连接时状态可能还是「离线」，稍等 30 秒心跳后就变「空闲在线」。\n'; fi
  return 0
}

ensure_service() {
  if agent_running; then return 0; fi
  notify_as "ZogToken" "正在设置为后台常驻…"
  local out
  out=$(curl -fsSL "$SERVER/install" | /bin/bash -s -- --service --server="$SERVER" 2>&1)
  if [ $? -eq 0 ]; then return 0; fi
  alert_as "后台常驻设置失败：

$out

（设备已连接，但关闭终端后会停止上报。可稍后在控制台用安装命令重试。）"
  return 1
}

# ---------- 主流程 ----------
TOKEN=$(cat "$TOKEN_FILE" 2>/dev/null)

if [ -n "$TOKEN" ]; then
  ST=$(platform_status 2>/dev/null) || ST="本地已有设备令牌，但平台未确认（可能是密钥已被停用或设备被解绑）。"
  C=$(choice_as "本机已接入 ZogToken。

$ST

要做什么？" "查看连接状态" "重新连接（换密钥）" "停止并退出")
  case "$C" in
    "查看连接状态") platform_status >/dev/null 2>&1 ;;
    "停止并退出")
      launchctl bootout "gui/$(id -u)/$LABEL" >/dev/null 2>&1
      launchctl unload -w "$PLIST" >/dev/null 2>&1
      alert_as "已停止后台常驻上报。设备仍保留在平台「设备列表」中，可在控制台解绑。"
      exit 0
      ;;
  esac
  [ "$C" = "查看连接状态" ] && { alert_as "$(platform_status 2>&1)"; exit 0; }
  : > "$TOKEN_FILE"
fi

# 登录页
KEY=""
while :; do
  RES=$(ask_as "ZogToken 节点接入

服务器：$SERVER

在控制台「令牌管理」生成 Group Key 后，粘贴到这里点「连接」：
（格式 ZOG-XXXX-XXXX-XXXX）" "$KEY" "退出" "连接")
  BTN="${RES%%|*}"; TXT="${RES#*|}"
  [ "$BTN" = "退出" ] && exit 0
  KEY=$(printf '%s' "$TXT" | tr -d ' \t\r\n' | tr 'a-z' 'A-Z')
  case "$KEY" in
    ZOG-????-????-????) : ;;
    *) alert_as "Group Key 格式不对：$KEY

应形如 ZOG-XXXX-XXXX-XXXX（4 段）。请回控制台「令牌管理」重新复制。"; continue ;;
  esac
  notify_as "ZogToken" "正在连接平台…"
  OUT=$(curl -fsSL "$SERVER/install" | /bin/bash -s -- "$KEY" --server="$SERVER" --register-only 2>&1)
  if [ $? -eq 0 ] && [ -s "$TOKEN_FILE" ]; then
    ensure_service
    ST=$(platform_status 2>&1)
    C=$(choice_as "连接成功！

$ST" "查看状态" "打开控制台" "关闭")
    if [ "$C" = "打开控制台" ]; then open "$SERVER/console"; fi
    if [ "$C" = "查看状态" ]; then alert_as "$(platform_status 2>&1)"; fi
    exit 0
  fi
  C=$(choice_as "连接失败：

$OUT" "重试" "改地址" "退出")
  case "$C" in
    退出) exit 0 ;;
    改地址)
      R2=$(ask_as "平台服务器地址（形如 https://你的域名，不要带结尾斜杠）：" "$SERVER" "取消" "确定")
      B2="${R2%%|*}"; S2=$(printf '%s' "${R2#*|}" | tr -d ' \t\r\n' | sed 's|/$||')
      if [ "$B2" = "确定" ] && [ -n "$S2" ]; then
        SERVER="$S2"
        sed -i '' "s|^SERVER=.*|SERVER=\"$SERVER\"|" "$0" 2>/dev/null || true
      fi
      ;;
  esac
done
APPMAIN

# 注入平台地址（占位符替换）
/usr/bin/sed -i '' "s|https://uwhats.com/zogtoken|$SERVER|g" "$APPDIR/Contents/MacOS/ZogToken" 2>/dev/null || \
  sed -i "s|https://uwhats.com/zogtoken|$SERVER|g" "$APPDIR/Contents/MacOS/ZogToken"
chmod 755 "$APPDIR/Contents/MacOS/ZogToken"
chmod 644 "$APPDIR/Contents/Info.plist"

# 图标（拉取失败不影响使用）
curl -fsSL "$SERVER/app/icon.icns" -o "$APPDIR/Contents/Resources/icon.icns" >/dev/null 2>&1 || log "图标下载失败（不影响使用）"

# 去掉隔离属性并登记到 LaunchServices（本地生成的文件一般无隔离属性，这里兜底）
xattr -cr "$APPDIR" >/dev/null 2>&1
/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -f "$APPDIR" >/dev/null 2>&1

log "已生成：$APPDIR"
log "打开方式：Finder → 应用程序（或 ~/Applications）→ 双击 $APP_NAME"
log "正在打开…"
open "$APPDIR"
