#!/bin/bash
###############################################################################
#   Copyright 2025 BITart Gerd Knops, All rights reserved.
#
#   Project : GerdsToolSet
#   File    : notarizeAndPackage
#   Author  : Gerd Knops gerti@BITart.com
#
###############################################################################
#
#   Notarize and package a macOS app for distribution.
#   Called from postArchiveHook with Xcode environment variables set.
#
#   Required environment variables:
#     ARCHIVE_PATH           - Path to .xcarchive
#     ARCHIVE_PRODUCTS_PATH  - Path to Products inside archive
#     FULL_PRODUCT_NAME      - e.g., "Claup.app"
#     PRODUCT_NAME           - e.g., "Claup"
#     MARKETING_VERSION      - e.g., "26.2"
#     DEVELOPMENT_TEAM       - e.g., "4SPFFPWZW7"
#     PROJECT_DIR            - Project root directory
#     BUILD_DIR              - Xcode build directory (for intermediate files)
#
###############################################################################

set -e

# Notarytool keychain profile name
NOTARY_PROFILE="notarytool"

# Working directory (uses Xcode build dir)
WORK_DIR="${BUILD_DIR:-/tmp}/Release"

# Output directory for final distribution
DIST_DIR="$WORK_DIR/dist"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

###############################################################################
# Functions
###############################################################################

log_info() {
    echo -e "${GREEN}==>${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}Warning:${NC} $1"
}

log_error() {
    echo -e "${RED}Error:${NC} $1" >&2
}

die() {
    log_error "$1"
    echo
    echo "Press any key to close..."
    read -n 1
    exit 1
}

check_environment() {
    log_info "Checking environment..."

    # Verify required variables
    : "${ARCHIVE_PATH:?ARCHIVE_PATH not set}"
    : "${ARCHIVE_PRODUCTS_PATH:?ARCHIVE_PRODUCTS_PATH not set}"
    : "${FULL_PRODUCT_NAME:?FULL_PRODUCT_NAME not set}"
    : "${PRODUCT_NAME:?PRODUCT_NAME not set}"
    : "${MARKETING_VERSION:?MARKETING_VERSION not set}"
    : "${DEVELOPMENT_TEAM:?DEVELOPMENT_TEAM not set}"
    : "${PROJECT_DIR:?PROJECT_DIR not set}"

    # Check archive exists
    if [[ ! -d "$ARCHIVE_PATH" ]]; then
        die "Archive not found: $ARCHIVE_PATH"
    fi

    # Check for notarytool credentials (skip if bypassing notarization).
    #
    # `notarytool history` is a live call to Apple, so a failure here does not
    # necessarily mean the keychain profile is missing — it also fails on an
    # expired Apple Developer agreement (HTTP 403), a network problem, or an
    # Apple service outage. Capture the real error and only suggest
    # store-credentials when the profile genuinely looks absent.
    if [[ "$SKIP_NOTARIZATION" != "1" ]]; then
        local notary_out
        if ! notary_out=$(xcrun notarytool history --keychain-profile "$NOTARY_PROFILE" 2>&1); then
            if echo "$notary_out" | grep -qiE 'keychain|profile'; then
                die "Notarytool profile '$NOTARY_PROFILE' not found. Run: xcrun notarytool store-credentials $NOTARY_PROFILE"
            fi

            die "notarytool could not verify credentials for profile '$NOTARY_PROFILE'.
A 403 about an agreement means an Apple Developer agreement has lapsed — sign in
as the Account Holder at https://developer.apple.com/account (and check App Store
Connect > Business > Agreements) to accept it, then retry.
Original error:
$notary_out"
        fi
    fi
}

export_app() {
    log_info "Exporting app from archive..."

    EXPORT_PATH="$WORK_DIR/Export"
    mkdir -p "$EXPORT_PATH"

    # Create export options plist
    local export_options="$WORK_DIR/ExportOptions.plist"
    cat > "$export_options" << EOF
<?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>developer-id</string>
    <key>teamID</key>
    <string>$DEVELOPMENT_TEAM</string>
    <key>signingStyle</key>
    <string>manual</string>
    <key>signingCertificate</key>
    <string>Developer ID Application</string>
</dict>
</plist>
EOF

    xcodebuild -exportArchive \
        -archivePath "$ARCHIVE_PATH" \
        -exportPath "$EXPORT_PATH" \
        -exportOptionsPlist "$export_options" \
        -quiet

    # ditto -c -k creates AppleDouble files (._*) from extended attributes.
    # This happens because ditto preserves extended attributes in ZIPs as AppleDouble files.
    # We'll switch to using zip command instead, which does not create them.
}

notarize_app() {
    if [[ "$SKIP_NOTARIZATION" == "1" ]]; then
        log_warn "SKIP_NOTARIZATION=1, skipping notarization"
        return
    fi

    local app_path="$EXPORT_PATH/$FULL_PRODUCT_NAME"
    local zip_for_notary="$WORK_DIR/${PRODUCT_NAME}-notarize.zip"

    log_info "Creating zip for notarization..."
    (cd "$EXPORT_PATH" && zip -r -y "$zip_for_notary" "$FULL_PRODUCT_NAME" 2>/dev/null)

    log_info "Submitting to Apple for notarization (this may take a few minutes)..."
    xcrun notarytool submit "$zip_for_notary" \
        --keychain-profile "$NOTARY_PROFILE" \
        --wait

    log_info "Stapling notarization ticket..."
    xcrun stapler staple "$app_path"

    # Clean up notarization zip
    rm -f "$zip_for_notary"
}

create_distribution_zip() {
    ZIP_PATH="$DIST_DIR/${PRODUCT_NAME}-${MARKETING_VERSION}.zip"

    mkdir -p "$DIST_DIR"

    log_info "Creating distribution zip..."
    (cd "$EXPORT_PATH" && zip -r -y "$ZIP_PATH" "$FULL_PRODUCT_NAME" 2>/dev/null)
}

resolve_icon_path() {
    # Mirrors CopyAppIconPhaseScript: prefer source PNG, fall back to extracting
    # from the compiled .icns inside the exported .app via iconutil.
    local src_png="$PROJECT_DIR/$PRODUCT_NAME/Resources/Assets.xcassets/AppIcon.appiconset/icon_256x256.png"

    if [[ -f "$src_png" ]]; then
        ICON_PATH="$src_png"
        return
    fi

    local icns="$EXPORT_PATH/$FULL_PRODUCT_NAME/Contents/Resources/$PRODUCT_NAME.icns"

    if [[ ! -f "$icns" ]]; then
        log_warn "Neither source icon nor $PRODUCT_NAME.icns found"
        ICON_PATH=""
        return
    fi

    local tmp_iconset="$WORK_DIR/$PRODUCT_NAME.iconset"
    rm -rf "$tmp_iconset"

    if ! iconutil -c iconset -o "$tmp_iconset" "$icns"; then
        log_warn "Failed to extract iconset from $icns"
        ICON_PATH=""
        return
    fi

    local extracted="$tmp_iconset/icon_256x256.png"
    [[ -f "$extracted" ]] || extracted="$tmp_iconset/icon_128x128@2x.png"

    if [[ ! -f "$extracted" ]]; then
        log_warn "256x256 icon not found in extracted iconset"
        rm -rf "$tmp_iconset"
        ICON_PATH=""
        return
    fi

    ICON_PATH="$WORK_DIR/icon_256x256.png"
    cp "$extracted" "$ICON_PATH"
    rm -rf "$tmp_iconset"
}

persist_archive_state() {
    # Append ZIP_PATH/ICON_PATH so updateSite can be re-run argument-free against
    # the same archive (e.g. while iterating on Site/index.md or HTML templates).
    local env_file="${GTS_ARCHIVE_ENV_FILE:-}"
    [[ -z "$env_file" ]] && return
    [[ ! -f "$env_file" ]] && return

    cat >> "$env_file" << EOF
export ZIP_PATH="$ZIP_PATH"
export ICON_PATH="$ICON_PATH"
EOF
}

update_site() {
    local update_site_script="$PROJECT_DIR/GerdsToolSet/Xcode/buildScripts/updateSite"

    if [[ ! -x "$update_site_script" ]]; then
        log_warn "updateSite script not found or not executable: $update_site_script"
        return
    fi

    resolve_icon_path

    if [[ -z "$ICON_PATH" ]]; then
        log_warn "Skipping site update (no icon resolved)"
        return
    fi

    persist_archive_state

    "$update_site_script" "$ZIP_PATH" "$ICON_PATH"
}

show_summary() {
    echo
    echo "============================================="
    echo -e "${GREEN}Release $MARKETING_VERSION complete!${NC}"
    echo "============================================="
    echo
    echo "Distribution zip ($(du -h "$ZIP_PATH" | cut -f1)):"
    echo "  $ZIP_PATH"
    echo
}

###############################################################################
# Main
###############################################################################

echo
echo "============================================="
echo "  Notarize and Package: $PRODUCT_NAME $MARKETING_VERSION"
echo "============================================="
echo

check_environment
export_app
notarize_app
create_distribution_zip
update_site
show_summary
