#!/usr/bin/env bash

# Determine the path to this script (we'll use this to figure out relative positions of other files)
SOURCE="${BASH_SOURCE[0]}"
if [ -h "$SOURCE" ]; then
  while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
    PREV_DIR="$(dirname "$SOURCE")"
    SOURCE="$(readlink "$SOURCE")"
    SOURCE_NAME="$(basename "$SOURCE")"
    # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
    if [[ $SOURCE != /* ]]; then
      SCRIPT_PATH="$( cd -P "${PREV_DIR}/$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
      SOURCE="$SCRIPT_PATH/$SOURCE_NAME"
    else
      SCRIPT_PATH="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
    fi
  done
else
  SCRIPT_PATH="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
fi

# Check if we are running 'Dev Mode' and if so, override values for devs
SCRIPT_BASENAME=$(basename "$SCRIPT_PATH")
if [ "${SCRIPT_BASENAME}" == "bin" ]; then
  # we can be running dev mode with a symlink to the package/dist/bin folder. In this case, our relative path is two levels up.
  export QUARTO_ROOT="`cd "$SCRIPT_PATH/../../.." > /dev/null 2>&1 && pwd`"
elif [ "${SCRIPT_BASENAME}" == "common" ]; then
  # we can run this script directly in the source tree. In this case, our relative path is three levels up.
  export QUARTO_ROOT="`cd "$SCRIPT_PATH/../../.." > /dev/null 2>&1 && pwd`"
else
  echo "ERROR: Cannot determine the Quarto source path. This script must be run from the bin or common folder."
  exit 1
fi
QUARTO_SRC_PATH="$QUARTO_ROOT/src"
DEV_PATH=$QUARTO_SRC_PATH/quarto.ts

if [ -f "$DEV_PATH" ]; then
  QUARTO_DEV_MODE=true
  QUARTO_IMPORT_MAP_ARG=--importmap=$QUARTO_SRC_PATH/import_map.json
  if [ "$1" == "--version" ] || [ "$1" == "-v" ]; then
    if [ "$QUARTO_FORCE_VERSION" != "" ]; then
      echo $QUARTO_FORCE_VERSION
      exit 0
    fi
    echo "99.9.9"
    exit 0
  fi

  # Caller can point deno at another entry point (e.g. the typescript file)
  if [ -z ${QUARTO_ACTION+x} ]; then
    QUARTO_ACTION=run
  fi

  # Turn on type checking for dev version
  if [ -z ${QUARTO_NO_TYPECHECK+x} ]; then
    QUARTO_DENO_OPTIONS=--check
  fi

  # Allow calls to override the target
  if [ -z ${QUARTO_TARGET+x} ]; then
    QUARTO_TARGET=$DEV_PATH
  fi
  
  export QUARTO_BIN_PATH=$SCRIPT_PATH
  export QUARTO_SHARE_PATH="${QUARTO_SHARE_PATH=$QUARTO_SRC_PATH/resources/}"
  export DENO_DIR=$QUARTO_BIN_PATH/deno_cache

  if [ -z ${QUARTO_DEBUG+x} ]; then
    export QUARTO_DEBUG=true
  fi
  QUARTO_CACHE_OPTIONS="--cached-only"

  # Check for deno update
  QUARTO_DIST_CONFIG=$QUARTO_BIN_PATH/../config
  mkdir -p $QUARTO_DIST_CONFIG
  DENO_VERSION_FILE=$QUARTO_DIST_CONFIG/deno-version
  DENO_SOURCE_VERSION="`(cd "$QUARTO_ROOT" && source ./configuration && echo $DENO)`"
  if [ -f "$DENO_VERSION_FILE" ]; then
    # echo is to trim whitespace to avoid version comparison issues
    DENO_INSTALLED_VERSION=$(echo `cat "$DENO_VERSION_FILE"`)
    if [ "${DENO_SOURCE_VERSION}" != "${DENO_INSTALLED_VERSION}" ]; then
      # configure will call back into this script so we need to update the
      # version so that the check will pass next time through
      (cd "$QUARTO_ROOT" && ./configure.sh)
      echo ""
      printf "\\033[0;31mQuarto required reconfiguration to install Deno. Had ${DENO_INSTALLED_VERSION}, needed ${DENO_SOURCE_VERSION}. Please try command again.\\033[0m\n\n"
      exit 1
    fi
  fi

else
  QUARTO_ACTION=run
  QUARTO_TARGET=${SCRIPT_PATH}/quarto.js
  export QUARTO_BIN_PATH=$SCRIPT_PATH
  QUARTO_CACHE_OPTIONS="--cached-only"

  # Turn off type checking for bundled version
  QUARTO_DENO_OPTIONS=--no-check

  # If Quarto is bundled into an `.app` file, it will be looking for the
  # share directory over in the resources folder.
  if [ -z "${QUARTO_SHARE_PATH+x}" ]; then
    if [[ $SCRIPT_PATH == *"/Contents/MacOS/quarto/bin" ]]; then
      export QUARTO_SHARE_PATH="`cd "$SCRIPT_PATH/../../../Resources/quarto/share";pwd`"
    elif [[ $SCRIPT_PATH == *"/usr/local/bin/quarto" ]]; then
      export QUARTO_SHARE_PATH="`cd "$SCRIPT_PATH/../../share/quarto";pwd`"
    else
      export QUARTO_SHARE_PATH="`cd "$SCRIPT_PATH/../share";pwd`"
    fi
  fi

  if [ "$1" == "--version" ] || [ "$1" == "-v" ]; then
    if [ "$QUARTO_FORCE_VERSION" != "" ]; then
      echo $QUARTO_FORCE_VERSION
      exit 0
    fi
    echo `cat "$QUARTO_SHARE_PATH/version"`
    exit 0
  fi

fi

if [ "$1" == "--paths" ]; then
  echo "$QUARTO_BIN_PATH"
  echo "$QUARTO_SHARE_PATH"
  exit 0
fi

if [[ $OSTYPE == 'darwin'* ]]; then
  # We cannot use uname to determine the _machine_ architecture:
  # https://github.com/quarto-dev/quarto-cli/issues/2420#issuecomment-1245768732
  # However, sysctl can return unexpected values in sandboxed/virtualized environments.
  # Use sysctl -n to get just the value, and check multiple possible patterns.
  FULLARCH="$(/usr/sbin/sysctl -n machdep.cpu.brand_string 2>/dev/null)"

  if [[ $FULLARCH == *"Intel"* ]] || [[ $FULLARCH == *"Xeon"* ]] || [[ $FULLARCH == *"Core"* ]]; then
    ARCH_DIR=x86_64
  elif [[ $FULLARCH == *"Apple"* ]] || [[ $FULLARCH == *"ARM"* ]]; then
    ARCH_DIR=aarch64
  else
    # Fallback to uname -m if sysctl doesn't give us recognizable output
    # This helps with sandboxed/virtualized environments
    UNAME_ARCH=$(uname -m)
    if [[ $UNAME_ARCH == "x86_64" ]]; then
      ARCH_DIR=x86_64
    elif [[ $UNAME_ARCH == "arm64" ]]; then
      ARCH_DIR=aarch64
    else
      echo "quarto script failed: unrecognized architecture. sysctl returned: '${FULLARCH}', uname -m returned: '${UNAME_ARCH}'"
      exit 1
    fi
  fi

else
  NIXARCH=$(uname -m)
  if [[ $NIXARCH == "x86_64" ]]; then
    ARCH_DIR=x86_64
  elif [[ $NIXARCH == "aarch64" ]]; then
    ARCH_DIR=aarch64
  else
    echo "configure script failed: unrecognized architecture " ${NIXARCH}
    exit 1
  fi
fi


if [ "$QUARTO_DENO_DOM" != "" ]; then
  export DENO_DOM_PLUGIN=$QUARTO_DENO_DOM
elif [ "$(uname)" = "Darwin" ]; then
  export DENO_DOM_PLUGIN=$QUARTO_BIN_PATH/tools/${ARCH_DIR}/deno_dom/libplugin.dylib
else
  export DENO_DOM_PLUGIN=$QUARTO_BIN_PATH/tools/${ARCH_DIR}/deno_dom/libplugin.so
fi


if [ "$QUARTO_DENO" == "" ]; then
  DENO_ARCH_DIR=$ARCH_DIR
  export QUARTO_DENO="${SCRIPT_PATH}/tools/${DENO_ARCH_DIR}/deno"
fi

export DENO_TLS_CA_STORE=system,mozilla
export DENO_NO_UPDATE_CHECK=1
# Be sure to include any already defined QUARTO_DENO_OPTIONS
## Using --allow-all as there is otherwise an issue in Deno 1.46.3 with --allow-read and --allow-write with network drives
## https://github.com/quarto-dev/quarto-cli/issues/11332
QUARTO_DENO_OPTIONS="--unstable-ffi --unstable-kv --no-config --no-lock ${QUARTO_CACHE_OPTIONS} --allow-all ${QUARTO_DENO_OPTIONS}"

# --enable-experimental-regexp-engine is required for /regex/l, https://github.com/quarto-dev/quarto-cli/issues/9737
if [ "$QUARTO_DENO_V8_OPTIONS" != "" ]; then
  QUARTO_DENO_V8_OPTIONS="--enable-experimental-regexp-engine,--max-old-space-size=8192,--max-heap-size=8192,--stack-trace-limit=100,${QUARTO_DENO_V8_OPTIONS}"
else
  QUARTO_DENO_V8_OPTIONS="--enable-experimental-regexp-engine,--max-old-space-size=8192,--max-heap-size=8192,--stack-trace-limit=100"
fi

if [ "$QUARTO_DENO_EXTRA_OPTIONS" == "" ]; then
  QUARTO_DENO_EXTRA_OPTIONS="--v8-flags=${QUARTO_DENO_V8_OPTIONS}"
else
  QUARTO_DENO_EXTRA_OPTIONS="--v8-flags=${QUARTO_DENO_V8_OPTIONS} ${QUARTO_DENO_EXTRA_OPTIONS}"
fi

if [ "$QUARTO_TS_PROFILE" != "" ]; then
  QUARTO_DENO_EXTRA_OPTIONS="--inspect-brk ${QUARTO_DENO_EXTRA_OPTIONS}"
  QUARTO_TS_PROFILE=true "${QUARTO_DENO}" ${QUARTO_ACTION} ${QUARTO_DENO_OPTIONS} ${QUARTO_DENO_EXTRA_OPTIONS} "${QUARTO_IMPORT_MAP_ARG}" "${QUARTO_TARGET}" "$@"
else
  if [ "$QUARTO_DEV_MODE" == true ]; then
    "${QUARTO_DENO}" ${QUARTO_ACTION} ${QUARTO_DENO_OPTIONS} ${QUARTO_DENO_EXTRA_OPTIONS} "${QUARTO_IMPORT_MAP_ARG}" "${QUARTO_TARGET}" "$@" 
  else
    "${QUARTO_DENO}" ${QUARTO_ACTION} ${QUARTO_DENO_OPTIONS} ${QUARTO_DENO_EXTRA_OPTIONS} "${QUARTO_TARGET}" "$@" 
  fi
fi
