#!/bin/bash
# 產生 macOS 安裝檔（.dmg，內含「M.app」）。用法：packaging/build-macos.sh
# 輸出在 dist/ 底下。需要：cargo、Xcode（ibtool / codesign / hdiutil）。
# CEF 預設放在 ~/.local/share/cef，第一次編譯時 cef-dll-sys 會自動下載。
#
# .app 的結構照 CEF 的規定（https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md#markdown-header-macos）：
#   M.app/Contents/MacOS/vpn-cef-browser
#   M.app/Contents/Frameworks/Chromium Embedded Framework.framework
#   M.app/Contents/Frameworks/vpn-cef-browser Helper*.app   ← 5 個子行程用的 helper
# helper 的檔名一定要是「<主執行檔名> Helper (…)」，CEF 靠這個名字找它們。
#
# 簽章身分要固定：macOS 的鑰匙圈（Chromium 用它存 cookie 的加密金鑰）認的是程式的簽章，臨時簽章
# （ad-hoc）每個版本都不一樣，所以每個新版本第一次開都會被問一次「要不要讓這個 App 使用鑰匙圈」。
# 用固定的憑證簽，新版本的「身分要求」跟舊版一樣（識別碼 + 同一張憑證），就不會再問。選法：
#   1. 環境變數 SIGN_ID，例如 SIGN_ID="Developer ID Application: …" packaging/build-macos.sh
#   2. packaging/sign-id.local 的第一行（這台電腦專用，不進 git）
#   3. 這台電腦上第一個有效的「Apple Development: …」憑證
#   4. 都沒有才退回臨時簽章（-）：能用，但鑰匙圈每個新版本都會問一次
set -euo pipefail

cd "$(dirname "$0")/.."
ROOT="$PWD"
export CEF_PATH="${CEF_PATH:-$HOME/.local/share/cef}"
NAME=vpn-cef-browser
HELPER=vpn-cef-browser-helper
DISPLAY_NAME="M"
BUNDLE_ID=com.steps.vpn-cef-browser
VERSION=$(grep -m1 '^version' Cargo.toml | sed 's/.*"\(.*\)".*/\1/')
ARCH=$(uname -m)          # arm64（Apple Silicon）或 x86_64
if [ -z "${SIGN_ID:-}" ] && [ -f "$ROOT/packaging/sign-id.local" ]; then
  SIGN_ID="$(head -1 "$ROOT/packaging/sign-id.local")"
fi
if [ -z "${SIGN_ID:-}" ]; then
  SIGN_ID="$(security find-identity -v -p codesigning 2>/dev/null | sed -n 's/.*"\(Apple Development: [^"]*\)".*/\1/p' | head -1 || true)"
fi
SIGN_ID="${SIGN_ID:--}"
DIST="$ROOT/dist"
STAGE="$DIST/stage-mac"
APP="$STAGE/$DISPLAY_NAME.app"
FRAMEWORK="Chromium Embedded Framework.framework"
LOCALES="en en_GB zh_TW zh_CN"   # 只帶這幾個語系；其他語系 CEF 會退回 en

# 內建字型（全字庫正楷體，標楷體的替代）不在 git 裡，缺的話先下載
[ -f resources/fonts/TW-Kai-98_1.ttf ] || packaging/fetch-fonts.sh

# Google 雲端硬碟同步（src/shared/gdrive_sync.rs）用的 OAuth 用戶端 ID / 密鑰：公司在 Google Cloud 建一組（類型「電腦版應用程式」），
# 放在 packaging/google-oauth.local（第 1 行用戶端 ID、第 2 行用戶端密鑰；這台電腦專用，不進 git），或用環境變數
# VPN_GOOGLE_CLIENT_ID / VPN_GOOGLE_CLIENT_SECRET。編譯時會編進程式；沒有的話設定頁會說還沒設定（使用者可以在「進階」自己填）。
if [ -z "${VPN_GOOGLE_CLIENT_ID:-}" ] && [ -f "$ROOT/packaging/google-oauth.local" ]; then
  VPN_GOOGLE_CLIENT_ID="$(sed -n 1p "$ROOT/packaging/google-oauth.local" | tr -d '[:space:]')"
  VPN_GOOGLE_CLIENT_SECRET="$(sed -n 2p "$ROOT/packaging/google-oauth.local" | tr -d '[:space:]')"
fi
if [ -n "${VPN_GOOGLE_CLIENT_ID:-}" ]; then
  export VPN_GOOGLE_CLIENT_ID VPN_GOOGLE_CLIENT_SECRET="${VPN_GOOGLE_CLIENT_SECRET:-}"
  echo "（Google 雲端硬碟同步：已內建用戶端 ID）"
else
  echo "（Google 雲端硬碟同步：沒有內建用戶端 ID，使用者要在設定頁「進階」自己填）"
fi

echo "== 1/5 release 編譯 =="
# SKIP_BUILD=1：已經編譯好了就跳過（cargo 就算沒東西要編，也會把相依套件的原始碼重新解壓縮到 ~/.cargo/registry/src，磁碟很滿時會吃掉空間）
if [ -z "${SKIP_BUILD:-}" ]; then
  cargo build --release --bin "$NAME" --bin "$HELPER"
fi

# cef-dll-sys 會把 CEF 解到 $CEF_PATH/<版本>/ 底下
CEF_DIR=$(dirname "$(find "$CEF_PATH" -maxdepth 3 -type d -name "$FRAMEWORK" | head -1)")
[ -d "$CEF_DIR/$FRAMEWORK" ] || { echo "找不到 $FRAMEWORK（CEF_PATH=$CEF_PATH）" >&2; exit 1; }

# $1 = plist 路徑, $2 = 執行檔名, $3 = bundle id, $4 = 顯示名稱, $5 = 1 表示是 helper
write_plist() {
  local ui_element=""
  [ "$5" = 1 ] && ui_element="<key>LSUIElement</key><string>1</string>"
  cat > "$1" <<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>CFBundleDevelopmentRegion</key><string>en</string>
  <key>CFBundleDisplayName</key><string>$4</string>
  <key>CFBundleExecutable</key><string>$2</string>
  <key>CFBundleIconFile</key><string>AppIcon</string>
  <key>CFBundleIdentifier</key><string>$3</string>
  <key>CFBundleInfoDictionaryVersion</key><string>6.0</string>
  <key>CFBundleName</key><string>$4</string>
  <key>CFBundlePackageType</key><string>APPL</string>
  <key>CFBundleShortVersionString</key><string>$VERSION</string>
  <key>CFBundleVersion</key><string>$VERSION</string>
  <key>CFBundleSignature</key><string>????</string>
  <key>LSEnvironment</key><dict><key>MallocNanoZone</key><string>0</string></dict>
  <key>LSFileQuarantineEnabled</key><true/>
  <key>LSMinimumSystemVersion</key><string>11.0</string>
  <key>NSHighResolutionCapable</key><true/>
  <key>NSPrincipalClass</key><string>NSApplication</string>
  <key>NSMainNibFile</key><string>MainMenu</string>
  <key>NSSupportsAutomaticGraphicsSwitching</key><true/>
  <key>NSCameraUsageDescription</key><string>網頁要求使用相機</string>
  <key>NSMicrophoneUsageDescription</key><string>網頁要求使用麥克風</string>
  <key>NSBluetoothAlwaysUsageDescription</key><string>網頁要求使用藍牙</string>
  <key>NSWebBrowserPublicKeyCredentialUsageDescription</key><string>網頁要求使用通行金鑰</string>
  $ui_element
</dict>
</plist>
PLIST
}

echo "== 2/5 組 .app =="
rm -rf "$STAGE"
mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources" "$APP/Contents/Frameworks"
install -m 0755 "target/release/$NAME" "$APP/Contents/MacOS/$NAME"
write_plist "$APP/Contents/Info.plist" "$NAME" "$BUNDLE_ID" "$DISPLAY_NAME" 0
cp resources/mac/AppIcon.icns "$APP/Contents/Resources/AppIcon.icns"
mkdir -p "$APP/Contents/Resources/English.lproj"
cp resources/mac/English.lproj/InfoPlist.strings "$APP/Contents/Resources/English.lproj/"
xcrun ibtool --compile "$APP/Contents/Resources/English.lproj/MainMenu.nib" \
  resources/mac/English.lproj/MainMenu.xib
# 內建字型（docs.rs 的 kai_font 從 Contents/Resources/fonts 讀）
mkdir -p "$APP/Contents/Resources/fonts"
cp resources/fonts/TW-Kai-98_1.ttf resources/fonts/LICENSE-TW-Kai.txt "$APP/Contents/Resources/fonts/"

# framework 在同一個 APFS 磁碟上就用 clonefile（cp -c，寫入才複製，不佔額外空間、也快很多；之後簽章只改到少數區塊），
# 不行（跨磁碟、不是 APFS）才退回 ditto。兩種都保留 framework 裡的 symlink（cp -R 不跟隨 symlink）
if ! cp -cR "$CEF_DIR/$FRAMEWORK" "$APP/Contents/Frameworks/$FRAMEWORK" 2>/dev/null; then
  rm -rf "$APP/Contents/Frameworks/$FRAMEWORK"
  ditto "$CEF_DIR/$FRAMEWORK" "$APP/Contents/Frameworks/$FRAMEWORK"
fi
for lproj in "$APP/Contents/Frameworks/$FRAMEWORK/Resources/"*.lproj; do
  keep=0
  for l in $LOCALES; do [ "$(basename "$lproj" .lproj)" = "$l" ] && keep=1; done
  [ $keep = 1 ] || rm -rf "$lproj"
done

for suffix in "" " (GPU)" " (Renderer)" " (Plugin)" " (Alerts)"; do
  h="$NAME Helper$suffix"
  id_suffix=$(echo "$suffix" | tr -d ' ()' | tr 'A-Z' 'a-z')
  dir="$APP/Contents/Frameworks/$h.app"
  mkdir -p "$dir/Contents/MacOS"
  install -m 0755 "target/release/$HELPER" "$dir/Contents/MacOS/$h"
  write_plist "$dir/Contents/Info.plist" "$h" "$BUNDLE_ID.helper${id_suffix:+.$id_suffix}" "$h" 1
done

echo "== 3/5 strip =="
strip -x "$APP/Contents/MacOS/$NAME"
for dir in "$APP/Contents/Frameworks/"*Helper*.app; do
  strip -x "$dir/Contents/MacOS/"*
done

echo "== 4/5 簽章（${SIGN_ID}） =="
# 由內而外：framework 裡的 dylib → framework → helper → 主 app
find "$APP/Contents/Frameworks/$FRAMEWORK" -name '*.dylib' -exec codesign --force --sign "$SIGN_ID" {} \;
codesign --force --sign "$SIGN_ID" "$APP/Contents/Frameworks/$FRAMEWORK"
for dir in "$APP/Contents/Frameworks/"*Helper*.app; do
  codesign --force --sign "$SIGN_ID" "$dir"
done
codesign --force --sign "$SIGN_ID" "$APP"
codesign --verify --deep --strict "$APP"
if [ "$SIGN_ID" = "-" ]; then
  echo "⚠ 用的是臨時簽章：每個新版本第一次開，macOS 都會問一次鑰匙圈。要固定身分的話見這個檔案開頭的說明。"
else
  echo "簽章的身分要求（新版本都一樣才不會再被問鑰匙圈）："
  codesign -d -r- "$APP" 2>&1 | grep designated | sed 's/^# /  /'
fi

echo "== 5/5 產生 .dmg =="
DMG="$DIST/$DISPLAY_NAME-$VERSION-macos-$ARCH.dmg"
rm -f "$DMG"
ln -s /Applications "$STAGE/Applications"
hdiutil create -volname "$DISPLAY_NAME" -srcfolder "$STAGE" -ov -format ULFO "$DMG" >/dev/null
rm "$STAGE/Applications"
( cd "$DIST" && shasum -a 256 "$(basename "$DMG")" > "$(basename "$DMG").sha256" )

echo
echo "完成："
ls -lh "$DMG"
echo ".app 也留在 ${APP}，可以直接執行測試"
