#!/usr/bin/env bash
set -euo pipefail

# GoingsOn macOS Release Script
# Builds a release .dmg, codesigns with Developer ID, notarizes via the
# App Store Connect API key, staples the ticket, and verifies the result.
#
# Run on the Mac (mbp). Two signing modes:
#   default     -- GUI session, signs from the unlocked login.keychain.
#   --keychain  -- HEADLESS/REMOTE: builds an ephemeral Developer ID build
#                  keychain (dist/build-keychain.sh) so this works over SSH from
#                  fw13 without a GUI unlock. The signing identity is derived
#                  automatically from the imported .p12 -- no need to fill in
#                  SIGNING_IDENTITY.
#
# Org-transfer note: --keychain signs with whatever team the .p12 holds, so it
# works BEFORE the Apple Developer org transfer to the LLC. Notarization is the
# only step that needs the signature team to match the notary key's team, so
# pass --sign-only to defer notarization until the teams line up.
#
# Prerequisites:
#   - Xcode command line tools (codesign, stapler, spctl, xcrun notarytool)
#   - A Developer ID Application identity, either:
#       * installed in login.keychain (default GUI mode), or
#       * exported to a .p12 referenced by ~/.tauri/passwords.env (--keychain mode)
#   - App Store Connect API key (.p8) at API_KEY_PATH -- only for notarization
#   - Tauri updater signing key at ~/.tauri/goingson.key (for OTA artifacts)
#
# Usage:
#   ./dist/release-macos.sh                       # GUI: build + notarize + verify
#   ./dist/release-macos.sh --keychain            # remote: build keychain + notarize
#   ./dist/release-macos.sh --keychain --sign-only# remote: sign only, no notarize
#   ./dist/release-macos.sh --no-verify           # skip the post-build gate
#
# Remote invocation from fw13:
#   ssh mbp 'cd ~/Code/Apps/goingson && source ~/.tauri/passwords.env && \
#            ./dist/release-macos.sh --keychain --sign-only'

cd "$(dirname "$0")/.."

# --- Configuration ---
# Fill SIGNING_IDENTITY from the exact output of (run in a GUI Terminal):
#   security find-identity -v -p codesigning | grep "Developer ID Application"
# The 10-char team in parens MUST match the notary key's team (93C54W92UP),
# or notarization rejects the signature for a team mismatch.
SIGNING_IDENTITY="${APPLE_SIGNING_IDENTITY:-Developer ID Application: FILL_ME (93C54W92UP)}"

# App Store Connect API credentials come from the environment, never from this
# file: this script is version-controlled and the repo is mirrored publicly.
# Issuer + key id are two thirds of the notary credential (the .p8 is the third),
# so they live in ~/.tauri/passwords.env, which is not in git. Only notarization
# reads them, so --sign-only does not require them.
API_KEY_ID="${APPLE_API_KEY_ID:-}"
API_ISSUER_ID="${APPLE_API_ISSUER_ID:-}"
API_KEY_PATH="${APPLE_API_KEY_PATH:-}"

DMG_GLOB="target/release/bundle/dmg/*.dmg"
APP_GLOB="target/release/bundle/macos/GoingsOn.app"
DIST_DIR="${HOME}/Dist/goingson/macos"

# --- Parse args ---
VERIFY=true
USE_KEYCHAIN=false
NOTARIZE=true
for arg in "$@"; do
    case "$arg" in
        --no-verify) VERIFY=false ;;
        --keychain)  USE_KEYCHAIN=true ;;
        --sign-only) NOTARIZE=false ;;
        -h|--help)
            echo "Usage: $0 [--keychain] [--sign-only] [--no-verify]"
            exit 0
            ;;
    esac
done

# --- Read version from tauri.conf.json ---
VERSION=$(python3 -c "import json; print(json.load(open('src-tauri/tauri.conf.json'))['version'])")
echo "Version: $VERSION"

# --- Signing identity: ephemeral build keychain (remote) or login.keychain (GUI) ---
if [ "$USE_KEYCHAIN" = true ]; then
    # shellcheck source=dist/build-keychain.sh
    source "$(dirname "$0")/build-keychain.sh"
    trap bk_teardown EXIT
    bk_setup
    SIGNING_IDENTITY="$(bk_identity_name)"
    if [ -z "$SIGNING_IDENTITY" ]; then
        echo "Error: no Developer ID Application identity in the build keychain."
        echo "Check BUILD_P12_PATH points at a Developer ID Application .p12."
        exit 1
    fi
    echo "Build-keychain identity: $SIGNING_IDENTITY"
fi

# --- Preflight ---
if [[ "$SIGNING_IDENTITY" == *FILL_ME* ]]; then
    echo "Error: SIGNING_IDENTITY is still the placeholder."
    echo "Either pass --keychain (derives it from the .p12) or set APPLE_SIGNING_IDENTITY"
    echo "from: security find-identity -v -p codesigning | grep 'Developer ID Application'"
    exit 1
fi
if [ "$NOTARIZE" = true ]; then
    # All three are required to notarize, and all three now come from the
    # environment. Check them together: passing an empty issuer/key id through to
    # Tauri fails deep inside notarytool with a far less obvious message.
    missing=""
    [ -n "$API_KEY_ID" ]    || missing="$missing APPLE_API_KEY_ID"
    [ -n "$API_ISSUER_ID" ] || missing="$missing APPLE_API_ISSUER_ID"
    [ -n "$API_KEY_PATH" ]  || missing="$missing APPLE_API_KEY_PATH"
    if [ -n "$missing" ]; then
        echo "Error: notarization needs:$missing"
        echo "Source the env file first (source ~/.tauri/passwords.env), or pass --sign-only."
        exit 1
    fi
    if [ ! -f "$API_KEY_PATH" ]; then
        echo "Error: API key not found at $API_KEY_PATH (check APPLE_API_KEY_PATH, or pass --sign-only)"
        exit 1
    fi
fi
if [ "$USE_KEYCHAIN" != true ] && ! security find-identity -v -p codesigning | grep -qF "$SIGNING_IDENTITY"; then
    echo "Error: identity not found in keychain: $SIGNING_IDENTITY"
    echo "Are you in a GUI session with login.keychain unlocked? (or pass --keychain for remote signing)"
    exit 1
fi
if [ -z "${GOINGSON_TAURI_PASSWORD:-}" ]; then
    echo "Note: GOINGSON_TAURI_PASSWORD unset -- source ~/.tauri/passwords.env first if you want OTA updater artifacts signed."
fi

# --- Build + sign (+ notarize + staple) ---
# Setting APPLE_API_ISSUER + APPLE_API_KEY + APPLE_API_KEY_PATH is what flips
# Tauri from "sign only" to "sign + notarize + staple" in one pass. With
# --sign-only those are omitted, so Tauri signs but does not notarize -- the
# org-transfer-deferral path (no team match needed to sign).
echo ""
if [ "$NOTARIZE" = true ]; then
    echo "=== Building, signing, and notarizing macOS release ==="
else
    echo "=== Building and signing macOS release (--sign-only, no notarization) ==="
fi
build_env=(
    "APPLE_SIGNING_IDENTITY=$SIGNING_IDENTITY"
    "TAURI_SIGNING_PRIVATE_KEY=${TAURI_SIGNING_PRIVATE_KEY:-$HOME/.tauri/goingson.key}"
    "TAURI_SIGNING_PRIVATE_KEY_PASSWORD=${TAURI_SIGNING_PRIVATE_KEY_PASSWORD:-${GOINGSON_TAURI_PASSWORD:-}}"
)
if [ "$NOTARIZE" = true ]; then
    build_env+=(
        "APPLE_API_ISSUER=$API_ISSUER_ID"
        "APPLE_API_KEY=$API_KEY_ID"
        "APPLE_API_KEY_PATH=$API_KEY_PATH"
    )
fi
# `app` MUST be in the bundle list for the updater artifact (.app.tar.gz + .sig)
# to be produced — `updater` alone with only `dmg` builds nothing updater-enabled
# ("no updater-enabled targets were built"). The .app is also what OTA ships.
env "${build_env[@]}" cargo tauri build --bundles app dmg updater

DMG_PATH=$(ls -t $DMG_GLOB 2>/dev/null | head -1 || true)
if [ -z "$DMG_PATH" ]; then
    echo "Error: no .dmg produced under target/release/bundle/dmg/"
    exit 1
fi
echo "Built: $DMG_PATH"

# --- Verify (the real release gate) ---
# Tauri/codesign can exit 0 with a bundle that Gatekeeper still rejects, so
# verify explicitly instead of trusting the build's exit code.
if [ "$VERIFY" = true ]; then
    echo ""
    echo "=== Verifying signature ==="
    # Tauri removes the intermediate .app after bundling the DMG, so it may be
    # gone by now — the DMG (stapler + spctl below) is the real gate.
    if [ -d "$APP_GLOB" ]; then
        echo "--- codesign (app) ---"
        codesign --verify --deep --strict --verbose=2 "$APP_GLOB"
    else
        echo "--- codesign (app): skipped, .app cleaned after bundling ---"
    fi
    if [ "$NOTARIZE" = true ]; then
        # Tauri notarizes + staples the .app but NOT the .dmg, so the disk image
        # itself has no ticket. Notarize + staple the DMG so it is Gatekeeper-clean
        # on mount (not just the app inside it).
        echo "--- notarize + staple (dmg) ---"
        xcrun notarytool submit "$DMG_PATH" \
            --key "$API_KEY_PATH" --key-id "$API_KEY_ID" --issuer "$API_ISSUER_ID" --wait
        xcrun stapler staple "$DMG_PATH"
        xcrun stapler validate "$DMG_PATH"
        echo "--- spctl (Gatekeeper) ---"
        # Expect: "accepted" with "source=Notarized Developer ID".
        if ! spctl -a -vvv -t install "$DMG_PATH" 2>&1 | tee /dev/stderr | grep -q "source=Notarized Developer ID"; then
            echo "Error: DMG is not Gatekeeper-accepted as Notarized Developer ID."
            exit 1
        fi
    else
        # Sign-only: confirm the signature exists and report the signing team, but
        # do NOT assert Gatekeeper acceptance -- an un-notarized DMG is rejected on
        # other Macs by design (right-click-open works for hand-picked beta testers).
        echo "--- codesign (signing authority / team) ---"
        codesign -dvvv "$APP_GLOB" 2>&1 | grep -E 'Authority|TeamIdentifier' || true
        echo "Note: --sign-only -- DMG is signed but NOT notarized; Gatekeeper will"
        echo "      flag it on other Macs until you re-run without --sign-only post-transfer."
    fi
fi

# --- Stage artifacts ---
mkdir -p "$DIST_DIR"
cp "$DMG_PATH" "$DIST_DIR/"
# Updater artifacts (.app.tar.gz + .sig) for OTA, if produced.
find target/release/bundle/macos -maxdepth 1 \( -name '*.app.tar.gz' -o -name '*.app.tar.gz.sig' \) \
    -exec cp {} "$DIST_DIR/" \; 2>/dev/null || true

echo ""
echo "Done. GoingsOn macOS v$VERSION"
echo "DMG staged at: $DIST_DIR/$(basename "$DMG_PATH")"
echo "Next: clean-account DMG smoke test, then upload updater artifacts via the MNW dashboard."
