#!/usr/bin/env bash
#
# Builds a Galaxy binary and bundles it up for distribution.

set -e

# On macOS, we need to use LLVM's clang for wasm32-unknown-unknown target
if [[ "$OSTYPE" == "darwin"* ]]; then
  LLVM_CLANG="/opt/homebrew/opt/llvm/bin/clang"
  if [ ! -f "$LLVM_CLANG" ]; then
    echo "Error: LLVM clang not found at $LLVM_CLANG"
    echo "Please install it with: brew install llvm"
    exit 1
  fi
  export CC_wasm32_unknown_unknown="$LLVM_CLANG"
fi

WORKSPACE_ROOT_DIR="$(pwd)"
CARGO_TARGET_DIR="$WORKSPACE_ROOT_DIR/target/wasm32-unknown-unknown"

# Build the OSS bundle.
RELEASE_CHANNEL="oss"
FEATURES="release_bundle,gui"
DEBUG=false

PARAMS=""
while (( "$#" )); do
  case "$1" in
    --debug)
      DEBUG=true
      shift
      ;;
    --check-only)
      echo 'Only running `cargo check` and not producing a bundle.'
      CHECK_ONLY="true"
      shift
      ;;
    --no-split)
      NO_SPLIT="true"
      shift
      ;;
    --nouniversal)
      # Discard the --nouniversal argument, which is only used for macOS
      # bundles.
      shift
      ;;
    -c|--channel)
      if [ -n "$2" ] && [ "${2:0:1}" != "-" ]; then
        RELEASE_CHANNEL=$2
        shift 2
      else
        echo "Error: Argument for $1 is missing" >&2
        exit 1
      fi
      ;;
    --release-tag)
      if [ -n "$2" ] && [ "${2:0:1}" != "-" ]; then
        echo "Setting release tag to $2"
        export GIT_RELEASE_TAG=$2
        shift 2
      else
        echo "Error: Argument for $1 is missing" >&2
        exit 1
      fi
      ;;
    --features)
      if [ -n "$2" ] && [ "${2:0:1}" != "-" ]; then
        echo "Setting features to $2"
        FEATURES_OVERRIDE=$2
        shift 2
      else
        echo "Error: Argument for $1 is missing" >&2
        exit 1
      fi
      ;;
    *) # preserve positional arguments
      PARAMS="$PARAMS $1"
      shift
      ;;
  esac
done
# set positional arguments in their proper place
eval set -- "$PARAMS"

if [[ $DEBUG = true ]]; then
  CARGO_PROFILE="dev-wasm"
else
  CARGO_PROFILE="release-wasm"
fi

# The `dev` profile needs to be special-cased for historical
# reasons: https://doc.rust-lang.org/cargo/guide/build-cache.html#build-cache.
# We don't use the `dev` profile today when bundling for wasm
# but this is left in the script to future-proof the use of the `dev` profile.
if [[ "$CARGO_PROFILE" == "dev" ]]; then
  CARGO_TARGET_OUTPUT_DIR="$CARGO_TARGET_DIR/debug"
else
  CARGO_TARGET_OUTPUT_DIR="$CARGO_TARGET_DIR/$CARGO_PROFILE"
fi

OUT_DIR="$CARGO_TARGET_OUTPUT_DIR/bundle/wasm"
mkdir -p "$OUT_DIR"
ASSET_TARGET_DIR="$CARGO_TARGET_OUTPUT_DIR/bundle/assets"
mkdir -p "$ASSET_TARGET_DIR"
EXTRAS_DIR="$CARGO_TARGET_OUTPUT_DIR/bundle/extras"
mkdir -p "$EXTRAS_DIR"

if [[ "$RELEASE_CHANNEL" != "oss" ]]; then
  echo "Error: only the oss release channel is supported" >&2
  exit 1
fi

# OSS is the only supported release channel.
GALAXY_BIN="galaxy-oss"

if [ -n "${FEATURES_OVERRIDE+x}" ]; then
  FEATURES="$FEATURES_OVERRIDE"
fi

# If we only want to check that compilation will succeed, perform the checks
# then exit.  We use this script to invoke `cargo check` to ensure that we are
# using the same feature flags and profile that we would be using in production.
if [[ "$CHECK_ONLY" == "true" ]]; then
  ASSET_TARGET_DIR="$ASSET_TARGET_DIR" cargo check --package galaxy --target wasm32-unknown-unknown --profile "$CARGO_PROFILE" --bin "$GALAXY_BIN" --features "$FEATURES"
  exit 0
fi

# Build the wasm binary.
echo "Building and bundling Galaxy for channel $RELEASE_CHANNEL"
ASSET_TARGET_DIR="$ASSET_TARGET_DIR" cargo build --package galaxy --target wasm32-unknown-unknown --profile "$CARGO_PROFILE" --bin "$GALAXY_BIN" --features "$FEATURES"

# Generate linked JS and wasm files that can be run in the browser.
echo "Running wasm-bindgen on $CARGO_TARGET_OUTPUT_DIR/$GALAXY_BIN.wasm"
wasm-bindgen --target web --out-dir "$OUT_DIR" --out-name "galaxy" --keep-debug --no-typescript "$CARGO_TARGET_OUTPUT_DIR/$GALAXY_BIN.wasm"

WASM_BINARY_OUT="${OUT_DIR}/galaxy_bg.wasm"
WASM_BINARY_DEBUG="${EXTRAS_DIR}/galaxy_bg.debug.wasm"

if [[ "$NO_SPLIT" != "true" ]]; then
  # Run Sentry's wasm-split binary to separate out debug information from the
  # wasm binary.
  #
  # Binary releases of wasm-split can be found here:
  # https://github.com/getsentry/symbolicator/releases
  wasm-split "$WASM_BINARY_OUT" --debug-out "$WASM_BINARY_DEBUG" --strip --strip-names
fi

# If this is being run within a GitHub action, set an output variable with the
# directory containing all built packages.
if [ "${GITHUB_ACTIONS}" == "true" ]; then
  echo "::echo::on"
  echo "packages_dir=$OUT_DIR" >> "$GITHUB_OUTPUT"
  echo "assets_dir=$ASSET_TARGET_DIR" >> "$GITHUB_OUTPUT"
  echo "debug_executable_path=$WASM_BINARY_DEBUG" >> "$GITHUB_OUTPUT"
  echo "::echo::off"
fi
