#!/usr/bin/env bash
#
# dist-ios-adhoc.sh — build an ad-hoc IPA of the iOS client and the files needed to
# install it on registered devices from an HTTPS web page (itms-services OTA install).
#
# This is for handing the app to a handful of friends BEFORE TestFlight. Ad-hoc builds
# only run on devices whose UDID is registered in your Apple Developer account, so the
# script registers UDIDs (via the App Store Connect API) before it signs.
#
# Pipeline:
#   1. Register each --udid with App Store Connect (idempotent; skip with --skip-register).
#   2. Build VoiceCatCore.xcframework (iOS device slice).
#   3. xcodebuild archive (Release, generic/platform=iOS), letting Xcode auto-create the
#      ad-hoc Distribution cert + profile via -allowProvisioningUpdates + the API key.
#   4. xcodebuild -exportArchive with method=release-testing (Xcode's modern name for
#      "ad-hoc") -> VoiceCatiOS.ipa.
#   5. Generate manifest.plist (OTA install manifest) + index.html (install page).
#   6. Stage VoiceCatiOS.ipa + manifest.plist + index.html into dist/ios-adhoc/.
#
# You then upload those three files to your HTTPS host and open index.html on the iPhone.
#
# Prerequisites (one-time, not scriptable):
#   - Paid Apple Developer Program membership (Team ID is already set in the project).
#   - An App Store Connect API "Team Key" (.p8) with Admin or App Manager access:
#       App Store Connect -> Users and Access -> Integrations -> App Store Connect API.
#     Note its Key ID and Issuer ID. Keep the .p8 out of the repo.
#   - Each friend's device UDID (read it in Finder with the iPhone connected to a Mac).
#
# Auth — supply via env vars (or the matching flags):
#   ASC_KEY_ID      App Store Connect API Key ID          (--key-id)
#   ASC_ISSUER_ID   App Store Connect API Issuer ID       (--issuer-id)
#   ASC_KEY_PATH    path to AuthKey_XXXXXXXXXX.p8          (--key)
#
# Usage:
#   scripts/dist-ios-adhoc.sh --udid <UDID> --name "Friend iPhone" \
#       --base-url https://example.com/voicecat
#   scripts/dist-ios-adhoc.sh --udids-file friends.csv --base-url https://example.com/vc
#   scripts/dist-ios-adhoc.sh --skip-register --base-url https://example.com/vc  # rebuild only
#   scripts/dist-ios-adhoc.sh --dist /out --no-configure
#   scripts/dist-ios-adhoc.sh -h|--help
#
# Flags:
#   --udid <UDID>        device to register (repeatable). Pair with an optional --name.
#   --name <label>       label for the immediately-preceding --udid (default: the UDID).
#   --udids-file <file>  CSV of "udid,name" lines (one device per line; blank/# lines skipped).
#   --base-url <url>     public HTTPS folder you'll upload the output to. Used to fill
#                        manifest.plist + index.html. If omitted, a __BASE_URL__ placeholder
#                        is written and you must edit both files before they work.
#   --skip-register      don't touch App Store Connect; just rebuild/export/stage.
#   --key-id / --issuer-id / --key   override the ASC_* env vars.
#   --dist <path>        output root (default <repo>/dist). Files land in <dist>/ios-adhoc/.
#   --no-configure       skip the cmake configure step in the xcframework build.
#   -h, --help           this help.
#
# macOS only. Requires Xcode, VCPKG_ROOT (or a configured build/apple-dev cache), and the
# Python `cryptography` package (already present in a standard macOS Python 3).
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
VC_SCRIPT_NAME="dist-ios-adhoc"
source "$SCRIPT_DIR/common.sh"

# ── Project constants (see clients/apple/iOS/VoiceCatiOS.xcodeproj) ───────────────
TEAM_ID="FJV8L966W4"
APP_BUNDLE_ID="cat.voice.VoiceCatiOS"
SCHEME="VoiceCatiOS"
APP_TITLE="VoiceCat"
XCODEPROJ="$VC_REPO_ROOT/clients/apple/iOS/VoiceCatiOS.xcodeproj"

# ── Args ──────────────────────────────────────────────────────────────────────────
KEY_ID="${ASC_KEY_ID:-}"
ISSUER_ID="${ASC_ISSUER_ID:-}"
KEY_PATH="${ASC_KEY_PATH:-}"
BASE_URL=""
SKIP_REGISTER=false
DO_CONFIGURE=true
UDIDS=()        # parallel arrays: UDIDS[i] / UDID_NAMES[i]
UDID_NAMES=()

while [[ $# -gt 0 ]]; do
    case "$1" in
        --udid)        UDIDS+=("$2"); UDID_NAMES+=("$2"); shift 2 ;;
        --name)        [[ ${#UDID_NAMES[@]} -gt 0 ]] || vc_die "--name must follow a --udid"
                       UDID_NAMES[${#UDID_NAMES[@]}-1]="$2"; shift 2 ;;
        --udids-file)  [[ -f "$2" ]] || vc_die "udids file not found: $2"
                       while IFS=',' read -r u n _; do
                           u="${u// /}"
                           [[ -z "$u" || "$u" == \#* ]] && continue
                           UDIDS+=("$u"); UDID_NAMES+=("${n:-$u}")
                       done < "$2"
                       shift 2 ;;
        --base-url)    BASE_URL="${2%/}"; shift 2 ;;
        --skip-register) SKIP_REGISTER=true; shift ;;
        --key-id)      KEY_ID="$2"; shift 2 ;;
        --issuer-id)   ISSUER_ID="$2"; shift 2 ;;
        --key)         KEY_PATH="$2"; shift 2 ;;
        --dist)        vc_set_dist "$2"; shift 2 ;;
        --no-configure) DO_CONFIGURE=false; shift ;;
        -h|--help)     vc_print_help "$0"; exit 0 ;;
        *) vc_die "unknown arg: $1 (try --help)" ;;
    esac
done

vc_require_macos

# Auth is needed for device registration AND for -allowProvisioningUpdates (Xcode uses the
# same key to mint the ad-hoc Distribution cert/profile).
[[ -n "$KEY_ID"    ]] || vc_die "missing API Key ID (set ASC_KEY_ID or pass --key-id)"
[[ -n "$ISSUER_ID" ]] || vc_die "missing Issuer ID (set ASC_ISSUER_ID or pass --issuer-id)"
[[ -n "$KEY_PATH"  ]] || vc_die "missing .p8 path (set ASC_KEY_PATH or pass --key)"
[[ -f "$KEY_PATH"  ]] || vc_die "API key file not found: $KEY_PATH"
python3 -c "import cryptography" 2>/dev/null \
    || vc_die "Python 'cryptography' package not available: pip3 install cryptography"

if [[ -z "$BASE_URL" ]]; then
    BASE_URL="__BASE_URL__"
    vc_log "no --base-url given: manifest.plist + index.html will use the __BASE_URL__"
    vc_log "placeholder — edit both files to your real HTTPS folder before uploading."
fi

OUT="$(vc_dist_subdir ios-adhoc)"
ARCHIVE="$OUT/VoiceCatiOS.xcarchive"
EXPORT_DIR="$OUT/export"
DERIVED="$OUT/DerivedData"
IPA="$OUT/VoiceCatiOS.ipa"

# ── Step 1: register devices ───────────────────────────────────────────────────────
if $SKIP_REGISTER; then
    vc_step "skipping device registration (--skip-register)"
elif [[ ${#UDIDS[@]} -eq 0 ]]; then
    vc_step "no --udid/--udids-file given — skipping device registration"
    vc_log "(devices must already be registered, or this IPA won't install for them)"
else
    vc_step "register ${#UDIDS[@]} device(s) with App Store Connect"
    for i in "${!UDIDS[@]}"; do
        python3 "$SCRIPT_DIR/asc_api.py" register \
            --key-id "$KEY_ID" --issuer-id "$ISSUER_ID" --key "$KEY_PATH" \
            --udid "${UDIDS[$i]}" --name "${UDID_NAMES[$i]}"
    done
    vc_ok "device registration complete"
fi

# ── Step 2: xcframework (iOS device slice) ──────────────────────────────────────────
vc_step "build VoiceCatCore.xcframework (iOS device slice)"
vc_resolve_vcpkg_root "apple-dev"
XCFW_ARGS=( --preset apple-ios )
$DO_CONFIGURE || XCFW_ARGS+=( --no-configure )
"$VC_REPO_ROOT/clients/apple/scripts/build-xcframework.sh" "${XCFW_ARGS[@]}"
XCFW="$VC_REPO_ROOT/clients/apple/VoiceCatCore.xcframework"
[[ -d "$XCFW" ]] || vc_die "xcframework not found at $XCFW"
vc_ok "xcframework ready -> $XCFW"

# ── Step 3: archive ─────────────────────────────────────────────────────────────────
vc_step "xcodebuild archive ($SCHEME / Release / generic iOS)"
xcodebuild archive \
    -project "$XCODEPROJ" \
    -scheme "$SCHEME" \
    -configuration Release \
    -destination 'generic/platform=iOS' \
    -archivePath "$ARCHIVE" \
    -derivedDataPath "$DERIVED" \
    -allowProvisioningUpdates \
    -authenticationKeyPath "$KEY_PATH" \
    -authenticationKeyID "$KEY_ID" \
    -authenticationKeyIssuerID "$ISSUER_ID"
[[ -d "$ARCHIVE" ]] || vc_die "archive not produced at $ARCHIVE"
vc_ok "archived -> $ARCHIVE"

# ── Step 4: export ad-hoc IPA ───────────────────────────────────────────────────────
# method "release-testing" is Xcode 15.3+/26's name for the old "ad-hoc" method.
# manageAppGroups lets automatic signing carry the group.cat.voice.VoiceCat capability
# (used by the ReplayKit broadcast extension) into the generated profiles.
EXPORT_PLIST="$OUT/ExportOptions.plist"
cat > "$EXPORT_PLIST" <<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>method</key>            <string>release-testing</string>
    <key>teamID</key>            <string>$TEAM_ID</string>
    <key>signingStyle</key>      <string>automatic</string>
    <key>manageAppGroups</key>   <true/>
    <key>stripSwiftSymbols</key> <true/>
</dict>
</plist>
PLIST

vc_step "xcodebuild -exportArchive (method=release-testing / ad-hoc)"
xcodebuild -exportArchive \
    -archivePath "$ARCHIVE" \
    -exportPath "$EXPORT_DIR" \
    -exportOptionsPlist "$EXPORT_PLIST" \
    -allowProvisioningUpdates \
    -authenticationKeyPath "$KEY_PATH" \
    -authenticationKeyID "$KEY_ID" \
    -authenticationKeyIssuerID "$ISSUER_ID"

EXPORTED_IPA="$(find "$EXPORT_DIR" -maxdepth 1 -name '*.ipa' | head -n1)"
[[ -n "$EXPORTED_IPA" ]] || vc_die "no .ipa found in $EXPORT_DIR"
mv "$EXPORTED_IPA" "$IPA"
vc_ok "exported -> $IPA ($(du -h "$IPA" | cut -f1))"

# ── Step 5: read version + generate manifest.plist & index.html ─────────────────────
APP_IN_ARCHIVE="$(find "$ARCHIVE/Products/Applications" -maxdepth 1 -name '*.app' | head -n1)"
SHORT_VER="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' \
    "$APP_IN_ARCHIVE/Info.plist" 2>/dev/null || echo "1.0")"

MANIFEST="$OUT/manifest.plist"
cat > "$MANIFEST" <<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>items</key>
  <array>
    <dict>
      <key>assets</key>
      <array>
        <dict>
          <key>kind</key>             <string>software-package</string>
          <key>url</key>              <string>$BASE_URL/VoiceCatiOS.ipa</string>
        </dict>
      </array>
      <key>metadata</key>
      <dict>
        <key>bundle-identifier</key>  <string>$APP_BUNDLE_ID</string>
        <key>bundle-version</key>     <string>$SHORT_VER</string>
        <key>kind</key>               <string>software</string>
        <key>title</key>              <string>$APP_TITLE</string>
      </dict>
    </dict>
  </array>
</dict>
</plist>
PLIST

INDEX="$OUT/index.html"
cat > "$INDEX" <<HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Install $APP_TITLE</title>
  <style>
    body { font: 17px -apple-system, system-ui, sans-serif; margin: 0; padding: 2.5rem 1.5rem;
           color: #111; background: #f5f5f7; -webkit-text-size-adjust: 100%; }
    main { max-width: 30rem; margin: 0 auto; }
    h1 { font-size: 1.6rem; }
    .btn { display: block; text-align: center; text-decoration: none; margin: 1.5rem 0;
           padding: 0.9rem 1rem; border-radius: 0.8rem; background: #0a84ff; color: #fff;
           font-weight: 600; }
    .note { font-size: 0.9rem; color: #555; line-height: 1.5; }
    code { background: #e5e5ea; padding: 0.1rem 0.3rem; border-radius: 0.3rem; }
  </style>
</head>
<body>
  <main>
    <h1>$APP_TITLE — test build</h1>
    <p>Tap below on your <strong>iPhone</strong> to install (version $SHORT_VER).</p>
    <a class="btn" href="itms-services://?action=download-manifest&amp;url=$BASE_URL/manifest.plist">
      Install $APP_TITLE
    </a>
    <p class="note">
      Only works on devices whose UDID was registered for this build, on iOS 18 or later.
      If nothing happens, make sure you opened this page in <strong>Safari</strong> and that
      it is served over <strong>HTTPS</strong>. After installing, the app launches normally —
      no "trust developer" step is needed.
    </p>
  </main>
</body>
</html>
HTML

# ── Done ────────────────────────────────────────────────────────────────────────────
vc_ok "staged install files in $OUT:"
printf '       %s\n' "VoiceCatiOS.ipa" "manifest.plist" "index.html"
echo
if [[ "$BASE_URL" == "__BASE_URL__" ]]; then
    vc_log "NEXT: replace __BASE_URL__ in manifest.plist and index.html with your HTTPS"
    vc_log "      folder URL, then upload all three files there."
else
    vc_log "NEXT: upload the three files above to  $BASE_URL/"
    vc_log "      then open  $BASE_URL/index.html  in Safari on a registered iPhone."
fi
