#!/usr/bin/env bash
#
# local_test.sh — macOS 客户端本地联调一条龙(Developer ID 重签 + 装 + 跑)。
#
# 背景:flutter build 出来的包是 Apple Development 签名;要让 System Extension
# 能加载(且不依赖 SIP/dev mode),需重签成 Developer ID。本脚本封装这套流程。
#
# 子命令:
#   build   flutter build macos --release(注入联调节点地址)
#   sign    Developer ID 内向外重签整个 app + PacketTunnel sysext(嵌 DevID profile)
#   copy    覆盖安装到 /Applications
#   run     直跑 /Applications 版本(绕 Gatekeeper,实时输出日志,并打印测试账号)
#   all     依次执行 build → sign → copy → run
#
# 用法:  scripts/local_test.sh all   |   scripts/local_test.sh build   ...
set -euo pipefail

# ─────────── 配置(按需改)───────────
API_URL="http://103.119.13.48:8080"        # 联调控制面;发版改这里或走默认
SIGN_ID="Developer ID Application: Yanmei (beijing) Technology Co., Ltd (BYL4KQHMTN)"
APP_PROFILE_NAME="Pangolin App DevID"            # 主 app 的 Developer ID 描述文件名
SE_PROFILE_NAME="Pangolin PacketTunnel DevID"    # PacketTunnel 的描述文件名
TEST_EMAIL="wang880812@gmail.com"                # 联调测试账号
TEST_PASSWORD="pangolin2026"
NOTARY_PROFILE="pangolin-notary"                 # notarytool 凭据(已存入钥匙串)
# 注:DevID profile 已含 system-extension.install + NE(-systemextension 变体);
#     app/sysext entitlements 与之对齐(见 write_entitlements)。

# ─────────── 路径推导 ───────────
SRC="${BASH_SOURCE[0]}"
DIR="${SRC%/*}"; [ "$DIR" = "$SRC" ] && DIR="."
cd "$DIR/.."; REPO_ROOT="$PWD"
CLIENT="$REPO_ROOT/client"
APP="$CLIENT/build/macos/Build/Products/Release/pangolin_vpn.app"
SE="$APP/Contents/Library/SystemExtensions/PacketTunnel.systemextension"
LIBFW="$SE/Contents/Frameworks/Libbox.framework"
PROF_DIR="$HOME/Library/Developer/Xcode/UserData/Provisioning Profiles"
WORK="${TMPDIR:-/tmp}/pangolin_local_test"; mkdir -p "$WORK"

log(){ printf '\033[1;33m== %s ==\033[0m\n' "$*"; }
die(){ printf '\033[1;31m❌ %s\033[0m\n' "$*" >&2; exit 1; }

# 按 Name 在描述文件目录里定位 .provisionprofile(结果写入全局 FOUND)。
FOUND=""
find_profile(){
  local want="$1" f
  for f in "$PROF_DIR"/*.provisionprofile; do
    [ -e "$f" ] || continue
    if security cms -D -i "$f" 2>/dev/null | grep -q ">$want<"; then
      FOUND="$f"; return 0
    fi
  done
  return 1
}

write_entitlements(){
  cat > "$WORK/app.entitlements" <<'PLIST'
<?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>com.apple.application-identifier</key><string>BYL4KQHMTN.com.pangolin.pangolin</string>
	<key>com.apple.developer.team-identifier</key><string>BYL4KQHMTN</string>
	<key>com.apple.developer.system-extension.install</key><true/>
	<key>com.apple.developer.networking.networkextension</key>
	<array><string>packet-tunnel-provider-systemextension</string></array>
	<key>com.apple.security.app-sandbox</key><false/>
	<key>com.apple.security.network.client</key><true/>
	<key>com.apple.security.network.server</key><true/>
	<key>keychain-access-groups</key>
	<array><string>BYL4KQHMTN.com.pangolin.pangolin</string></array>
</dict></plist>
PLIST
  cat > "$WORK/sysext.entitlements" <<'PLIST'
<?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>com.apple.application-identifier</key><string>BYL4KQHMTN.com.pangolin.pangolin.PacketTunnel</string>
	<key>com.apple.developer.team-identifier</key><string>BYL4KQHMTN</string>
	<key>com.apple.developer.networking.networkextension</key>
	<array><string>packet-tunnel-provider-systemextension</string></array>
	<key>com.apple.security.app-sandbox</key><true/>
	<key>com.apple.security.application-groups</key>
	<array><string>group.com.pangolin.pangolin</string></array>
</dict></plist>
PLIST
}

cs(){ codesign --force --options runtime --timestamp "$@"; }

cmd_build(){
  log "构建 release(API=$API_URL)"
  cd "$CLIENT"
  flutter build macos --release --dart-define="PANGOLIN_API_URL=$API_URL"
  [ -d "$APP" ] || die "构建产物不存在: $APP"
}

cmd_sign(){
  [ -d "$APP" ] || die "先 build:找不到 $APP"
  log "Developer ID 重签"
  write_entitlements
  find_profile "$APP_PROFILE_NAME" || die "找不到描述文件: $APP_PROFILE_NAME"
  local app_prof="$FOUND"
  find_profile "$SE_PROFILE_NAME" || die "找不到描述文件: $SE_PROFILE_NAME"
  local se_prof="$FOUND"
  echo "  app profile : $app_prof"
  echo "  sysext prof : $se_prof"

  xattr -cr "$APP"
  cp "$app_prof" "$APP/Contents/embedded.provisionprofile"
  cp "$se_prof"  "$SE/Contents/embedded.provisionprofile"

  # 内向外:Libbox 真二进制 → Libbox.framework → sysext → app 各 framework → app 主体
  cs -s "$SIGN_ID" "$LIBFW/Versions/A/Libbox"
  cs -s "$SIGN_ID" "$LIBFW"
  cs --entitlements "$WORK/sysext.entitlements" -s "$SIGN_ID" "$SE"
  local item
  for item in "$APP/Contents/Frameworks/"*; do
    [ -e "$item" ] && cs -s "$SIGN_ID" "$item"
  done
  cs --entitlements "$WORK/app.entitlements" -s "$SIGN_ID" "$APP"

  codesign --verify --deep --strict "$APP" || die "深度校验失败"
  echo "  ✅ 重签 + 校验通过($SIGN_ID)"
}

cmd_notarize(){
  [ -d "$APP" ] || die "先 build/sign:找不到 $APP"
  log "公证(notarytool submit --wait,通常 1-5 分钟)"
  local zip="$WORK/pangolin_vpn.zip"
  rm -f "$zip"
  ditto -c -k --keepParent "$APP" "$zip"
  xcrun notarytool submit "$zip" --keychain-profile "$NOTARY_PROFILE" --wait
  log "staple 票据到 app"
  xcrun stapler staple "$APP"
  xcrun stapler validate "$APP" && echo "  ✅ 已公证 + staple"
}

cmd_copy(){
  [ -d "$APP" ] || die "先 build/sign:找不到 $APP"
  log "安装到 /Applications"
  osascript -e 'quit app "pangolin_vpn"' 2>/dev/null || true
  pkill -x pangolin_vpn 2>/dev/null || true
  sleep 1
  rm -rf /Applications/pangolin_vpn.app
  cp -R "$APP" /Applications/
  echo "  ✅ /Applications/pangolin_vpn.app"
}

cmd_run(){
  log "启动 /Applications/pangolin_vpn.app(直跑,日志见下)"
  echo ""
  echo "    测试账号: $TEST_EMAIL"
  echo "    测试密码: $TEST_PASSWORD"
  echo ""
  exec /Applications/pangolin_vpn.app/Contents/MacOS/pangolin_vpn
}

case "${1:-}" in
  build)    cmd_build ;;
  sign)     cmd_sign ;;     # 旧:手动 Developer ID 重签(现已由 Xcode 工程配置直接签,通常不需要)
  notarize) cmd_notarize ;;
  copy)     cmd_copy ;;
  run)      cmd_run ;;
  # Xcode 工程已配 Developer ID 手动签名(Release 配置),build 即出 DevID 包,无需 sign。
  all)      cmd_build; cmd_notarize; cmd_copy; cmd_run ;;
  *) echo "用法: $0 {all|build|sign|notarize|copy|run}"; exit 2 ;;
esac
