#!/bin/bash
# Sentry Bundle React Native code and images
# PWD=ios

# print commands before executing them and stop on first error
set -x -e

# WITH_ENVIRONMENT is executed by React Native

LOCAL_NODE_BINARY=${NODE_BINARY:-node}

# The project root by default is one level up from the ios directory
# SENTRY_PROJECT_ROOT can be set to override this for monorepo setups
# where the ios directory is not directly under the project root.
# See: https://github.com/getsentry/sentry-react-native/issues/2880
RN_PROJECT_ROOT="${SENTRY_PROJECT_ROOT:-${PROJECT_DIR}/..}"

[ -z "$SENTRY_PROPERTIES" ] && export SENTRY_PROPERTIES=sentry.properties
[ -z "$SENTRY_DOTENV_PATH" ] && [ -f "$RN_PROJECT_ROOT/.env.sentry-build-plugin" ] && export SENTRY_DOTENV_PATH="$RN_PROJECT_ROOT/.env.sentry-build-plugin"
[ -z "$SOURCEMAP_FILE" ] && export SOURCEMAP_FILE="$DERIVED_FILE_DIR/main.jsbundle.map"
# Resolve relative SOURCEMAP_FILE to absolute. The script runs from `ios/` (Xcode's PWD),
# but users typically specify paths relative to the project root. Without this, sentry-cli
# would resolve relative paths against `ios/` and fail to find the file.
# See: https://github.com/getsentry/sentry-react-native/issues/3889
if [[ "$SOURCEMAP_FILE" != /* ]]; then
  export SOURCEMAP_FILE="$(cd "$RN_PROJECT_ROOT" && pwd)/${SOURCEMAP_FILE#./}"
fi

if [ -z "$SENTRY_CLI_EXECUTABLE" ]; then
  # Resolve from @sentry/react-native so package managers with isolated dependencies
  # can find the transitive @sentry/cli dependency.
  RESOLVED_PATH=$(
    "$LOCAL_NODE_BINARY" --print "require('path').dirname(require.resolve('@sentry/cli/package.json', { paths: [require.resolve('@sentry/react-native/package.json')] }))" 2>/dev/null
  ) || true
  if [ -n "$RESOLVED_PATH" ]; then
    SENTRY_CLI_PACKAGE_PATH="$RESOLVED_PATH/bin/sentry-cli"
  else
    # Fallback: parse NODE_PATH from the .bin/sentry-cli shim (file generated by PNPM)
    PNPM_BIN_PATH="$PWD/../node_modules/@sentry/react-native/node_modules/.bin/sentry-cli"

    if [ -f "$PNPM_BIN_PATH" ]; then
      NODE_PATH_VALUE=$(grep -oE 'NODE_PATH="[^"]+"' "$PNPM_BIN_PATH" | head -n1 | sed -E 's/^NODE_PATH="([^"]*)"/\1/')
      # Split on ':' and pick the first entry containing `@sentry/cli/`. Handling each
      # entry separately avoids producing colon-joined garbage when the matching entry
      # isn't the first one in NODE_PATH.
      IFS=':' read -ra NODE_PATH_ENTRIES <<< "$NODE_PATH_VALUE"
      for entry in "${NODE_PATH_ENTRIES[@]}"; do
        if [[ "$entry" == *@sentry/cli/* ]]; then
          SENTRY_CLI_PACKAGE_PATH="${entry%%@sentry/cli/*}@sentry/cli/bin/sentry-cli"
          break
        fi
      done
    fi
  fi
fi
[ -z "$SENTRY_CLI_EXECUTABLE" ] && SENTRY_CLI_EXECUTABLE="$SENTRY_CLI_PACKAGE_PATH"

REACT_NATIVE_XCODE_DEFAULT="../node_modules/react-native/scripts/react-native-xcode.sh"
REACT_NATIVE_XCODE="${1:-$REACT_NATIVE_XCODE_DEFAULT}"

[[ "$AUTO_RELEASE" == false ]] && [[ -z "$BUNDLE_COMMAND" || "$BUNDLE_COMMAND" != "ram-bundle" ]] && NO_AUTO_RELEASE="--no-auto-release"
ARGS="--allow-xcode-infoplist-preprocessing $NO_AUTO_RELEASE $SENTRY_CLI_EXTRA_ARGS $SENTRY_CLI_RN_XCODE_EXTRA_ARGS"

REACT_NATIVE_XCODE_WITH_SENTRY="\"$SENTRY_CLI_EXECUTABLE\" react-native xcode $ARGS \"$REACT_NATIVE_XCODE\""

exitCode=0

if [ "$SENTRY_DISABLE_AUTO_UPLOAD" == true ]; then
  echo "SENTRY_DISABLE_AUTO_UPLOAD=true, skipping sourcemaps upload"
  /bin/sh -c "$REACT_NATIVE_XCODE"
elif echo "$CONFIGURATION" | grep -iq "debug"; then # case insensitive check for "debug"
  # Skip the source maps upload for *Debug* configuration, matching the behavior of the
  # native debug files upload (sentry-xcode-debug-files.sh) and the Android Gradle plugin.
  # Local Debug builds should not require Sentry credentials. Still run the React Native
  # bundling step so the build itself succeeds.
  # See: https://github.com/getsentry/sentry-react-native/issues/6399
  echo "Skipping source maps upload for *Debug* configuration"
  /bin/sh -c "$REACT_NATIVE_XCODE"
else
  # 'warning:' triggers a warning in Xcode, 'error:' triggers an error
  set +x +e # disable printing commands otherwise we might print `error:` by accident and allow continuing on error
  SENTRY_XCODE_COMMAND_OUTPUT=$(/bin/sh -c "\"$LOCAL_NODE_BINARY\" $REACT_NATIVE_XCODE_WITH_SENTRY" 2>&1)
  if [ $? -eq 0 ]; then
    echo "$SENTRY_XCODE_COMMAND_OUTPUT" | awk '{print "output: sentry-cli - " $0}'
  else
    if [ "$SENTRY_ALLOW_FAILURE" == true ]; then
      echo "$SENTRY_XCODE_COMMAND_OUTPUT" | awk '{print "warning: sentry-cli - " $0}'
      echo "warning: sentry-cli - Source maps upload failed, but continuing build because SENTRY_ALLOW_FAILURE=true"
    else
      echo "$SENTRY_XCODE_COMMAND_OUTPUT" | awk '{print "error: sentry-cli - " $0}'
      echo "error: sentry-cli - To disable source maps auto upload, set SENTRY_DISABLE_AUTO_UPLOAD=true in your environment variables. Or to allow failing upload, set SENTRY_ALLOW_FAILURE=true"
      exitCode=1
    fi
  fi
  set -x -e # re-enable
fi

[ -z "$SENTRY_COLLECT_MODULES" ] && SENTRY_RN_PACKAGE_PATH=$("$LOCAL_NODE_BINARY" --print "require('path').dirname(require.resolve('@sentry/react-native/package.json'))")
[ -z "$SENTRY_COLLECT_MODULES" ] && SENTRY_COLLECT_MODULES="${SENTRY_RN_PACKAGE_PATH}/scripts/collect-modules.sh"

if [ -f "$SENTRY_COLLECT_MODULES" ]; then
  /bin/sh "$SENTRY_COLLECT_MODULES"
fi

# sentry.options.json Block
SENTRY_OPTIONS_FILE_ERROR_MESSAGE_POSTFIX="Skipping options file copy. To disable this behavior, set SENTRY_COPY_OPTIONS_FILE=false in your environment variables."
SENTRY_OPTIONS_FILE_NAME="sentry.options.json"
SENTRY_OPTIONS_FILE_DESTINATION_PATH="$CONFIGURATION_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/$SENTRY_OPTIONS_FILE_NAME"
[ -z "$SENTRY_OPTIONS_FILE_PATH" ] && SENTRY_OPTIONS_FILE_PATH="$RN_PROJECT_ROOT/$SENTRY_OPTIONS_FILE_NAME"
[ -z "$SENTRY_COPY_OPTIONS_FILE" ] && SENTRY_COPY_OPTIONS_FILE=true

if [ "$SENTRY_COPY_OPTIONS_FILE" = true ]; then
  if [[ -z "$CONFIGURATION_BUILD_DIR" ]]; then
    echo "[Sentry] CONFIGURATION_BUILD_DIR is not set. $SENTRY_OPTIONS_FILE_ERROR_MESSAGE_POSTFIX" 1>&2
  elif [[ -z "$UNLOCALIZED_RESOURCES_FOLDER_PATH" ]]; then
    echo "[Sentry] UNLOCALIZED_RESOURCES_FOLDER_PATH is not set. $SENTRY_OPTIONS_FILE_ERROR_MESSAGE_POSTFIX" 1>&2
  elif [ ! -f "$SENTRY_OPTIONS_FILE_PATH" ]; then
    echo "[Sentry] $SENTRY_OPTIONS_FILE_PATH not found. $SENTRY_OPTIONS_FILE_ERROR_MESSAGE_POSTFIX" 1>&2
  else
    cp "$SENTRY_OPTIONS_FILE_PATH" "$SENTRY_OPTIONS_FILE_DESTINATION_PATH"

    if [ -n "$SENTRY_ENVIRONMENT" ] || [ -n "$SENTRY_RELEASE" ] || [ -n "$SENTRY_DIST" ]; then
      if "$LOCAL_NODE_BINARY" -e "
        var fs = require('fs');
        var destPath = process.argv[1];
        var opts = JSON.parse(fs.readFileSync(destPath, 'utf8'));
        if (process.env.SENTRY_ENVIRONMENT) { opts.environment = process.env.SENTRY_ENVIRONMENT; }
        if (process.env.SENTRY_RELEASE) { opts.release = process.env.SENTRY_RELEASE; }
        if (process.env.SENTRY_DIST) { opts.dist = process.env.SENTRY_DIST; }
        fs.writeFileSync(destPath, JSON.stringify(opts));
      " -- "$SENTRY_OPTIONS_FILE_DESTINATION_PATH" 2>/dev/null; then
        [ -n "$SENTRY_ENVIRONMENT" ] && echo "[Sentry] Overriding 'environment' from SENTRY_ENVIRONMENT environment variable"
        [ -n "$SENTRY_RELEASE" ] && echo "[Sentry] Overriding 'release' from SENTRY_RELEASE environment variable"
        [ -n "$SENTRY_DIST" ] && echo "[Sentry] Overriding 'dist' from SENTRY_DIST environment variable"
      else
        echo "[Sentry] Failed to override options from environment variables, copied file as-is." 1>&2
      fi
    fi
    echo "[Sentry] Copied $SENTRY_OPTIONS_FILE_PATH to $SENTRY_OPTIONS_FILE_DESTINATION_PATH"
  fi
fi

exit $exitCode
