#!/usr/bin/env bash
#
# One-command macOS release for a channel: build → sign (Developer ID) → notarize +
# staple the .app → build + sign the DMG → notarize + staple the DMG → (optionally)
# regenerate the Sparkle appcast.
#
#   scripts/release-macos.sh {beta|rc|stable}        # dev isn't a distribution channel
#
# Prerequisites (one-time — see signing/README.md):
#   • A "Developer ID Application" certificate in the keychain (auto-detected, or set
#     NUCLEIC_SIGN_ID to its identity string / hash).
#   • Notary credentials: a stored profile (NUCLEIC_NOTARY_PROFILE, default
#     'nucleic-notary') OR the NUCLEIC_ASC_* API-key env vars (see scripts/notarize.sh).
#
# Versioning: every release bumps the build number (CFBundleVersion) by 1 in ./VERSION, and
# bumps a semver component (CFBundleShortVersionString) — default minor, since we're pre-1.0.
# The new ./VERSION is committed on success (so versions/build numbers stay monotonic). Both the
# Makefile shortcut `make release-beta BUMP=major` and a direct `NUCLEIC_BUMP=build` work.
#
# Env:
#   NUCLEIC_SIGN_ID         signing identity (default: auto-detect Developer ID Application)
#   NUCLEIC_BUMP            semver bump: minor (default) | major | patch | build (build = build number only)
#   NUCLEIC_VERSION_COMMIT  commit the ./VERSION bump on success (default 1; 0 leaves it unstaged)
#   NUCLEIC_VERSION         pin the marketing version (overrides ./VERSION; forwarded to package-app.sh)
#   NUCLEIC_NOTARIZE_APP    notarize+staple the .app too (default 1; the DMG is always done)
#   NUCLEIC_APPCAST         regenerate the Sparkle appcast afterwards (default 1)
#   NUCLEIC_R2_UPLOAD       publish the DMG + appcast to R2 afterwards (default 1; needs wrangler)

set -euo pipefail

CHANNEL="${1:?usage: release-macos.sh (beta|rc|stable)}"
case "$CHANNEL" in
  beta)   APP_NAME="Nucleic Beta" ;;
  rc)     APP_NAME="Nucleic RC" ;;
  stable) APP_NAME="Nucleic" ;;
  dev)    echo "release-macos: 'dev' is a local channel, not for distribution. Use make app-dev." >&2; exit 2 ;;
  *) echo "usage: $0 {beta|rc|stable}" >&2; exit 2 ;;
esac

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"

# Resolve a Developer ID Application identity; refuse to "release" an ad-hoc build.
SIGN_ID="${NUCLEIC_SIGN_ID:-}"
if [ -z "$SIGN_ID" ]; then
  SIGN_ID="$(security find-identity -v -p codesigning 2>/dev/null \
    | grep 'Developer ID Application' | head -1 | sed -E 's/.*"([^"]+)".*/\1/')"
fi
if [ -z "$SIGN_ID" ] || [ "$SIGN_ID" = "-" ]; then
  cat >&2 <<EOF
release-macos: no "Developer ID Application" identity found.

Create one in Xcode → Settings → Accounts → (your paid team) → Manage Certificates
→ + → Developer ID Application, then re-run. Or set NUCLEIC_SIGN_ID explicitly.
Installed identities:
$(security find-identity -v -p codesigning 2>/dev/null | sed 's/^/  /')
EOF
  exit 1
fi
export NUCLEIC_SIGN_ID="$SIGN_ID"
echo "▸ Releasing $CHANNEL with identity: $SIGN_ID"

# 0. Bump the version: build number always +1, plus a semver bump (NUCLEIC_BUMP, default minor —
#    we're pre-1.0, so each release is a minor; major stays 0 until an explicit BUMP=major).
#    bump-version.sh rewrites ./VERSION; package-app.sh reads it on the very next line. If the
#    release fails before the artifact exists, an EXIT trap restores ./VERSION to its committed
#    value so a retry reuses the same number instead of skipping one. On success the bump is
#    committed (step 7); SUCCEEDED gates the trap so the bump survives.
SUCCEEDED=0
trap '[ "$SUCCEEDED" = 1 ] || git checkout -- VERSION 2>/dev/null || true' EXIT
BUMP="${NUCLEIC_BUMP:-minor}"
read -r REL_VERSION REL_BUILD <<EOF
$(scripts/bump-version.sh "$BUMP")
EOF
echo "▸ Version: $REL_VERSION (build $REL_BUILD)   [bump=$BUMP]"

# 1. Build + assemble + Developer-ID-sign the .app (picks up the bumped ./VERSION).
scripts/package-app.sh "$CHANNEL"

# 2. Notarize + staple the .app (so a copied-out app is trusted offline; default on).
APP="$ROOT/dist/$APP_NAME.app"
if [ "${NUCLEIC_NOTARIZE_APP:-1}" = "1" ]; then
  scripts/notarize.sh "$APP"
fi

# 3. Build + sign the DMG (from the now-stapled app).
scripts/make-dmg.sh "$CHANNEL"
plist="$APP/Contents/Info.plist"
SHORT_VERSION="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$plist")"
BUILD_NUMBER="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleVersion' "$plist")"
case "$CHANNEL" in beta) SLUG="Nucleic-Beta";; rc) SLUG="Nucleic-RC";; stable) SLUG="Nucleic";; esac
DMG="$ROOT/dist/${SLUG}-${SHORT_VERSION}.${BUILD_NUMBER}.dmg"

# 4. Notarize + staple the DMG.
scripts/notarize.sh "$DMG"

# The distributable artifact now exists and is notarized — the version is "spent". Keep the bump
# (the EXIT trap will no longer revert ./VERSION); steps 5–7 are post-processing.
SUCCEEDED=1

# 5. Regenerate the Sparkle appcast for this channel (default on; skipped if absent).
if [ "${NUCLEIC_APPCAST:-1}" = "1" ] && [ -x scripts/generate-appcast.sh ]; then
  scripts/generate-appcast.sh "$CHANNEL"
fi

# 6. Publish the DMG + appcast to R2 (updates.nucleic.blakeslee.xyz), the Sparkle feed host.
#    Default on; needs wrangler + R2 auth. Set NUCLEIC_R2_UPLOAD=0 to upload manually instead.
if [ "${NUCLEIC_R2_UPLOAD:-1}" = "1" ] && [ -x scripts/upload-r2.sh ]; then
  scripts/upload-r2.sh "$CHANNEL" \
    || echo "  (R2 upload skipped/failed — upload dist/ to the bucket manually; see signing/README.md)"
fi

# 7. Record the version bump (the release succeeded) so versions/build numbers stay monotonic
#    across releases. Off with NUCLEIC_VERSION_COMMIT=0 (then ./VERSION is left as a working
#    change for you to commit). A release that failed before step 4 had its ./VERSION restored by
#    the EXIT trap, so the next run reuses the same number rather than skipping one.
if [ "${NUCLEIC_VERSION_COMMIT:-1}" = "1" ] && ! git diff --quiet -- VERSION 2>/dev/null; then
  git add VERSION
  git commit -q -m "release($CHANNEL): v$REL_VERSION (build $REL_BUILD)" \
    && echo "▸ Committed version bump → v$REL_VERSION (build $REL_BUILD)"
fi

echo
echo "✓ Release artifact ready:"
echo "    $DMG"
echo "  Hosted via R2 at ${NUCLEIC_FEED_BASE:-https://updates.nucleic.blakeslee.xyz} (GitHub release is a fallback) — see signing/README.md."
