#!/bin/bash

set -e

build_flag="--release"
target_dir="release"
open_result=false
local_arch=false
local_only=false
overwrite_local_app=false
bundle_name=""

# Function for displaying help info
help_info() {
  echo "
Usage: ${0##*/} [options] [bundle_name]
Build the application bundle.

Options:
  -d    Compile in debug mode
  -l    Compile for local architecture and copy bundle to /Applications, implies -d.
  -o    Open the resulting DMG or the app itself in local mode.
  -f    Overwrite the local app bundle if it exists.
  -h    Display this help and exit.
  "
}

# If -o option is specified, the folder of the resulting dmg will be opened in finder
# If -d is specified, Zed will be compiled in debug mode and the application's path printed
# If -od or -do is specified Zed will be bundled in debug and the application will be run.
while getopts 'dlfoh' flag
do
    case "${flag}" in
        o) open_result=true;;
        d)
            export CARGO_INCREMENTAL=true
            export CARGO_BUNDLE_SKIP_BUILD=true
            build_flag="";
            local_arch=true
            target_dir="debug"
            ;;
        l)
            export CARGO_INCREMENTAL=true
            export CARGO_BUNDLE_SKIP_BUILD=true
            build_flag=""
            local_arch=true
            local_only=true
            target_dir="debug"
            ;;
        f) overwrite_local_app=true;;
        h)
           help_info
           exit 0
           ;;
    esac
done

shift $((OPTIND-1))

if [ "$1" ]; then
    bundle_name=$1
fi

export ZED_BUNDLE=true
export MACOSX_DEPLOYMENT_TARGET=10.15.7

cargo_bundle_version=$(cargo -q bundle --help 2>&1 | head -n 1 || echo "")
if [ "$cargo_bundle_version" != "cargo-bundle v0.6.0-zed" ]; then
    cargo install cargo-bundle --git https://github.com/zed-industries/cargo-bundle.git --branch zed-deploy
fi

rustup target add wasm32-wasi

# Deal with versions of macOS that don't include libstdc++ headers
export CXXFLAGS="-stdlib=libc++"

version_info=$(rustc --version --verbose)
host_line=$(echo "$version_info" | grep host)
local_target_triple=${host_line#*: }

if [ "$local_arch" = true ]; then
    echo "Building for local target only."
    cargo build ${build_flag} --package zed
    cargo build ${build_flag} --package cli
else
    echo "Compiling zed binary for aarch64-apple-darwin"
    cargo build ${build_flag} --package zed --target aarch64-apple-darwin
    echo "Compiling zed binary for x86_64-apple-darwin"
    cargo build ${build_flag} --package zed --target x86_64-apple-darwin
    echo "Compiling cli binary for aarch64-apple-darwin"
    cargo build ${build_flag} --package cli --target aarch64-apple-darwin
    echo "Compiling cli binary for x86_64-apple-darwin"
    cargo build ${build_flag} --package cli --target x86_64-apple-darwin
fi

echo "Creating application bundle"
pushd crates/zed
channel=$(<RELEASE_CHANNEL)
cp Cargo.toml Cargo.toml.backup
sed \
    -i .backup \
    "s/package.metadata.bundle-${channel}/package.metadata.bundle/" \
    Cargo.toml

if [ "$local_arch" = true ]; then
    app_path=$(cargo bundle ${build_flag} --select-workspace-root | xargs)
else
    app_path=$(cargo bundle ${build_flag} --target x86_64-apple-darwin --select-workspace-root | xargs)
fi

mv Cargo.toml.backup Cargo.toml
popd
echo "Bundled ${app_path}"

if [ "$local_arch" = false ]; then
    echo "Creating fat binaries"
    lipo \
        -create \
        target/{x86_64-apple-darwin,aarch64-apple-darwin}/${target_dir}/Zed \
        -output \
        "${app_path}/Contents/MacOS/zed"
    lipo \
        -create \
        target/{x86_64-apple-darwin,aarch64-apple-darwin}/${target_dir}/cli \
        -output \
        "${app_path}/Contents/MacOS/cli"
fi

echo "Copying WebRTC.framework into the frameworks folder"
mkdir "${app_path}/Contents/Frameworks"
if [ "$local_arch" = false ]; then
    cp -R target/${local_target_triple}/${target_dir}/WebRTC.framework "${app_path}/Contents/Frameworks/"
else
    cp -R target/${target_dir}/WebRTC.framework "${app_path}/Contents/Frameworks/"
fi

if [[ -n $MACOS_CERTIFICATE && -n $MACOS_CERTIFICATE_PASSWORD && -n $APPLE_NOTARIZATION_USERNAME && -n $APPLE_NOTARIZATION_PASSWORD ]]; then
    echo "Signing bundle with Apple-issued certificate"
    security create-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain || echo ""
    security default-keychain -s zed.keychain
    security unlock-keychain -p "$MACOS_CERTIFICATE_PASSWORD" zed.keychain
    echo "$MACOS_CERTIFICATE" | base64 --decode > /tmp/zed-certificate.p12
    security import /tmp/zed-certificate.p12 -k zed.keychain -P "$MACOS_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
    rm /tmp/zed-certificate.p12
    security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$MACOS_CERTIFICATE_PASSWORD" zed.keychain
    /usr/bin/codesign --force --deep --timestamp --options runtime --entitlements crates/zed/resources/zed.entitlements --sign "Zed Industries, Inc." "${app_path}" -v
    security default-keychain -s login.keychain
else
    echo "One or more of the following variables are missing: MACOS_CERTIFICATE, MACOS_CERTIFICATE_PASSWORD, APPLE_NOTARIZATION_USERNAME, APPLE_NOTARIZATION_PASSWORD"
    echo "Performing an ad-hoc signature, but this bundle should not be distributed"
    echo "If you see 'The application cannot be opened for an unexpected reason,' you likely don't have the necessary entitlements to run the application in your signing keychain"
    echo "You will need to download a new signing key from developer.apple.com, add it to keychain, and export MACOS_SIGNING_KEY=<email address of signing key>"
    codesign --force --deep --entitlements crates/zed/resources/zed.entitlements --sign ${MACOS_SIGNING_KEY:- -} "${app_path}" -v
fi

if [[ "$target_dir" = "debug" && "$local_only" = false ]]; then
    if [ "$open_result" = true ]; then
        open "$app_path"
    else
        echo "Created application bundle:"
        echo "$app_path"
    fi
    exit 0
fi

if [ "$local_only" = true ]; then
    # If bundle_name is not set or empty, use the basename of $app_path
    if [ -z "$bundle_name" ]; then
        bundle_name=$(basename "$app_path")
    else
        # If bundle_name doesn't end in .app, append it
        if [[ "$bundle_name" != *.app ]]; then
            bundle_name="$bundle_name.app"
        fi
    fi

    if [ "$overwrite_local_app" = true ]; then
        rm -rf "/Applications/$bundle_name"
    fi
    mv "$app_path" "/Applications/$bundle_name"

    if [ "$open_result" = true ]; then
        open "/Applications/$bundle_name"
    else
        echo "Installed application bundle:"
        echo "/Applications/$bundle_name"
    fi
else
    echo "Creating DMG"
    dmg_target_directory="target/${target_dir}"
    dmg_source_directory="${dmg_target_directory}/dmg"
    dmg_file_path="${dmg_target_directory}/Zed.dmg"

    rm -rf ${dmg_source_directory}
    mkdir -p ${dmg_source_directory}
    mv "${app_path}" "${dmg_source_directory}"

    ln -s /Applications ${dmg_source_directory}
    hdiutil create -volname Zed -srcfolder "${dmg_source_directory}" -ov -format UDZO "${dmg_file_path}"
    # If someone runs this bundle script locally, a symlink will be placed in `dmg_source_directory`.
    # This symlink causes CPU issues with Zed if the Zed codebase is the project being worked on, so we simply remove it for now.
    rm ${dmg_source_directory}/Applications

    echo "Adding license agreement to DMG"
    npm install --global dmg-license minimist
    dmg-license script/eula/eula.json "${dmg_file_path}"

    if [[ -n $MACOS_CERTIFICATE && -n $MACOS_CERTIFICATE_PASSWORD && -n $APPLE_NOTARIZATION_USERNAME && -n $APPLE_NOTARIZATION_PASSWORD ]]; then
        echo "Notarizing DMG with Apple"
        npm install -g notarize-cli
        npx notarize-cli --file "${dmg_file_path}" --bundle-id dev.zed.Zed --username "$APPLE_NOTARIZATION_USERNAME" --password "$APPLE_NOTARIZATION_PASSWORD"
    fi

    if [ "$open_result" = true ]; then
        open $dmg_target_directory
    fi
fi
