#!/usr/bin/env bash
#
# This is the AxonDeepSeg (ADS) installer
# It downloads the Conda (https://conda.pydata.org/) version
# of python and installs the ADS requirements over it
#
# The ADS can be installed in the location where you download it. If you choose to do so,
# do not delete the source code or you will delete the installation too!
#
# If you run the installer as super user, the default install is /opt,
# if you choose this option or any other directory other than the
# source location, you can get rid of the source code after the
# installation is successful.
#
# USAGE
#   ./install_ads [-h] [-i] [-y] [-g] [-d] [-b] [-v]
#
# OPTIONS
#  -h   Show this help
#  -i   Install in-place; this is the default when working from git.
#  -y   Install without interruption with 'yes' as default answer
#  -d   Prevent the (re)-installation of the data files (models, test data)
#  -c   Prevent checks from being run to validate the installation
#  -v   Full verbose
#
# Copyright (c) 2019 Polytechnique Montreal <www.neuro.polymtl.ca>
# License: see the file LICENSE


( # | tee install_ads_log.txt

# Change directory to where the script is, for the duration of the script.
cd "$(dirname "$0")" || exit 1

# stricter shell mode
# https://sipb.mit.edu/doc/safe-shell/
set -eo pipefail  # exit if non-zero error is encountered (even in a pipeline)
set -u            # exit if unset variables used
shopt -s failglob # error if a glob doesn't find any files, instead of remaining unexpanded

# set -v  # v: verbose

# Where tmp file are stored
TMP_DIR="$(mktemp -d 2>/dev/null || mktemp -d -t 'TMP_DIR')"
CONDA_DIR="ads_conda"
BIN_DIR="bin"
MACOSSUPPORTED="13"  # Minimum version of macOS 10 supported

# CLI options
ADS_INSTALL_TYPE=""
NONINTERACTIVE=""
NO_DATA_INSTALL=""
NO_INSTALL_VALIDATION=""
# Default value: 'master', however this value is updated on stable release branches.
ADS_GIT_REF="master"

# ======================================================================================================================
# FUNCTIONS
# ======================================================================================================================

# Print with color
# @input1: {info, code, error}: type of text
# rest of inputs: text to print
function print() {
  type=$1; shift
  case "$type" in
  # Display useful info (green)
  info)
    echo -e "\n\033[0;32m${*}\033[0m\n"
    ;;
  # To interact with user (no carriage return) (light green)
  question)
    echo -e -n "\n\033[0;92m${*}\033[0m"
    ;;
  # To display code that is being run in the Terminal (blue)
  code)
    echo -e "\n\033[0;34m${*}\033[0m\n"
    ;;
  # Warning message (yellow)
  warning)
    echo -e "\n\033[0;93m${*}\033[0m\n"
    ;;
  # Error message (red)
  error)
    echo -e "\n\033[0;31m${*}\033[0m\n"
    ;;
  esac
}

# Elegant exit with colored message
function die() {
  print error "$1"
  exit 1
}

# Run a command and display it in color. Exit if error.
# @input: string: command to run
function run() {
  ( # this subshell means the 'die' only kills this function and not the whole script;
    # the caller can decide what to do instead (but with set -e that usually means terminating the whole script)
    print code "$@"
    if ! "$@" ; then
      die "ERROR: Command failed."
    fi
  )
}

# Force a clean exit
# shellcheck disable=SC2317  # Don't warn about unreachable commands in this function, since it's invoked in a trap
function finish() {
  # Catch the last return code
  value="$?"
  if [[ "$value" -eq 0 ]]; then
    print info "Installation finished successfully!"
  elif [[ "$value" -eq 99 ]]; then
    # Showing usage with -h
    echo ""
  else
    print error "Installation failed!\n
Please find the file \"$PWD/install_ads_log.txt\",
then upload it as a .txt attachment in a new topic on AxonDeepSeg's forum:
--> https://github.com/axondeepseg/axondeepseg/discussions"
  fi
  # clean tmp_dir
  rm -rf "$TMP_DIR"
  exit "$value"
}

# reenable tty echo when user presses keyboard interrupt and output non-zero status for finish() function
# shellcheck disable=SC2317  # Don't warn about unreachable commands in this function, since it's invoked in a trap
detectKeyboardInterrupt() {
      # reenable tty echo
      print error "Installation aborted by the user."
      stty icanon echo echok
      exit 1
}

# Fetches the OS type
# @output: OS var is modified with the appropriate OS
function fetch_os_type() {
  print info "Checking OS type and version..."
  OSver="unknown"  # default value
  uname_output="$(uname -a)"
  echo "$uname_output"
  # macOS
  if echo "$uname_output" | grep -i darwin >/dev/null 2>&1; then
    # Fetch macOS version
    sw_vers_output="$(sw_vers | grep -e ProductVersion)"
    echo "$sw_vers_output"
    OSver="$(echo "$sw_vers_output" | cut -c 17-)"
    macOSmajor="$(echo "$OSver" | cut -f 1 -d '.')"
    macOSminor="$(echo "$OSver" | cut -f 2 -d '.')"
    # Make sure OSver is supported
    if [[ "${macOSmajor}" = 10 ]] && [[ "${macOSminor}" -lt "${MACOSSUPPORTED}" ]]; then
      die "Sorry, this version of macOS (10.$macOSminor) is not supported. The minimum version is 10.$MACOSSUPPORTED."
    fi
    # Fix for non-English Unicode systems on MAC
    if [[ -z "${LC_ALL:-}" ]]; then
      export LC_ALL=en_US.UTF-8
    fi

    if [[ -z "${LANG:-}" ]]; then
      export LANG=en_US.UTF-8
    fi
    OS="osx"
    PROCESSOR="$(uname -m)"
    # make sure bashrc is loaded when starting a new Terminal
    force_bashrc_loading
  # Linux
  elif echo "$uname_output" | grep -i linux >/dev/null 2>&1; then
    OS="linux"
    PROCESSOR="$(uname -m)"
  else
    die "Sorry, the installer only supports Linux and macOS, quitting installer"
  fi
}

# Checks if the necessary tools for ADS are installed on the machine
function check_requirements() {
  print info "Checking requirements..."
  # check curl
  if [[ ! ( $(command -v curl) || $(command -v wget) ) ]]; then
    die "ERROR: neither \"curl\" nor \"wget\" is installed. Please install either of them and restart ADS installation."
  fi
  # check rosetta
  if [[ "$OS" == "osx" ]]; then
    if ! arch -x86_64 true >/dev/null 2>&1; then
      print warning "WARNING: not running an x86_64 architecture."
      while [[ ! "$ROSETTA_INSTALL" =~ ^([Yy](es)?|[Nn]o?)$ ]]; do
        ROSETTA_INSTALL="no"
        if [ -z "$NONINTERACTIVE" ]; then
          print question "Do you want to install \"Rosetta 2\" now? [y]es/[n]o:"
          read -r ROSETTA_INSTALL
        fi
      done
      if [[ "$ROSETTA_INSTALL" =~ ^[Yy](es)? ]]; then
        softwareupdate --install-rosetta
        # check if we can now run x86_64 executables
        if ! arch -x86_64 true >/dev/null 2>&1; then
          die "ERROR: still cannot run x86_64 executables. Please contact ADS team for assistance."
        fi
      else
        die "Please install \"Rosetta 2\" by running \"softwareupdate --install-rosetta\" and restart ADS installation."
      fi
    fi
  fi
  # check gcc
  if ! gcc --version > /dev/null 2>&1; then
    print warning "WARNING: \"gcc\" is not installed."
    if [[ "$OS" == "osx" ]]; then
      while [[ ! "$GCC_INSTALL" =~ ^([Yy](es)?|[Nn]o?)$ ]]; do
        GCC_INSTALL="no"
        if [ -z "$NONINTERACTIVE" ]; then
          print question "Do you want to install it now? (accepting to install \"gcc\" will also install \"brew\" in case it is not installed already)? [y]es/[n]o: "
          read -r GCC_INSTALL
        fi
      done
      if [[ "$GCC_INSTALL" =~ [Yy](es)? ]]; then
        if [[ ! $(command -v brew) ]]; then
          # NB: this is a different NONINTERACTIVE than ours above; it's for the brew installer
          (NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)")
        fi
        brew install -f gcc
        # check if gcc install ran properly
        if ! gcc --version > /dev/null 2>&1; then
          die "ERROR: Installation of \"gcc\" failed. Please contact ADS team for assistance."
        fi
      else
        die "Please install \"gcc\" and restart ADS installation."
      fi
    else
      die "Please install \"gcc\" and restart ADS installation. On Debian/Ubuntu, run: \"apt install gcc\". On CentOS/RedHat, run: \"yum -y install gcc\"."
    fi
  fi
  print info "OK!"
}

# Gets the shell rc file path based on the default shell.
# @output: THE_RC and RC_FILE_PATH vars are modified
function get_shell_rc_path() {
  if [[ "$SHELL" == *"bash"* ]]; then
    THE_RC="bash"
    RC_FILE_PATH="$HOME/.bashrc"
  elif [[ "$SHELL" == *"/sh"* ]]; then
    THE_RC="bash"
    RC_FILE_PATH="$HOME/.bashrc"
  elif [[ "$SHELL" == *"zsh"* ]]; then
    THE_RC="bash"
    RC_FILE_PATH="$HOME/.zshrc"
  elif [[ "$SHELL" == *"csh"* ]]; then
    THE_RC="csh"
    RC_FILE_PATH="$HOME/.cshrc"
  else
    find ~/.* -maxdepth 0 -type f
    die "ERROR: Shell was not recognized: $SHELL"
  fi
}

# Force bashrc loading
function force_bashrc_loading() {
  sourceblock="
if [[ -n \"\$BASH_VERSION\" ]]; then
    # include .bashrc if it exists
    if [[ -f \"\$HOME/.bashrc\" ]]; then
    . \"\$HOME/.bashrc\"
    fi
fi"
  bidon=""
  for profile in ~/.bash_profile ~/.bash_login ~/.profile; do
    if [[ -a "$profile" ]]; then
      if ! grep -E "(\.|source) .*bashrc" "$profile" >/dev/null 2>&1; then
        echo "$sourceblock" >>"$profile"
      fi
      bidon="done"
      break
    fi
  done

  if [[ -z "$bidon" ]]; then
    echo "$sourceblock" >>~/.bash_profile
  fi
}

# Installation text to insert in shell config file
function edit_shellrc() {
  # Write text common to all shells
  (
    echo
    echo ""
    echo "# AXONDEEPSEG (installed on $(date +%Y-%m-%d\ %H:%M:%S))"
    echo "$DISPLAY_UPDATE_PATH"
    # Switch between shell
    if [[ "$THE_RC" == "bash" ]]; then
      echo "export ADS_DIR=$ADS_DIR"
    elif [[ "$THE_RC" == "csh" ]]; then
      echo "setenv ADS_DIR $ADS_DIR"
    fi
    # add line
    echo ""
    # Add ads_activate alias
    echo "alias ads_activate=\"source $ADS_DIR/ads_conda/bin/activate $ADS_DIR/ads_conda/envs/venv_ads/\""
    # add line
    echo ""
  ) >> "$RC_FILE_PATH"
}

# Download from URL using curl/wget
function download() {
  ( (command -v wget >/dev/null) && run wget -nv -O "$1" "$2" ) ||
  ( (command -v curl >/dev/null) && run curl -sS -o "$1" -L "$2" ) ||
  die "The download of $2 failed
Please check that you have wget or curl installed, and
your internet connection before relaunching the installer"
}

# Usage of this script
function usage() {
  # extract the usage block from our own header
  awk '
    BEGIN {
      printing=0
      blanks=0
    }

    # filter for block-comments
    $0 !~ /^#/   { next }
    # but strip any leading "# "
                 { sub("^#[[:space:]]?","") }

    # count consecutive blank lines
    # so we can detect the section break
    /^$/         { blanks++ }
    $0 !~ /^$/   { blanks=0 }

    # detect usage section
    /USAGE/      { printing=1 }
    printing==1  { print }
    (printing==1 && blanks>=2) { exit }
  ' "$0"
}

# ======================================================================================================================
# SCRIPT STARTS HERE
# ======================================================================================================================

# ----------------------------------------------------------------------------------------------------------------------
# CLI parser
# ----------------------------------------------------------------------------------------------------------------------

# Transform  long option "--long" into short option  "-l"
for arg in "$@"; do
  shift
  case "$arg" in
    *)       set -- "$@" "$arg"
  esac
done

while getopts ":iygdcvh" opt; do
  case $opt in
  i)
    ADS_INSTALL_TYPE="in-place"
    ;;
  y)
    echo " non-interactive mode"
    NONINTERACTIVE="yes"
    ;;
  d)
    echo " data directory will not be (re)-installed"
    NO_DATA_INSTALL="yes"
    ;;
  c)
    echo " no checks will be run (installation will not be validated)"
    NO_INSTALL_VALIDATION="yes"
    ;;
  v)
    echo " Full verbose!"
    set -x
    ;;
  h)
    usage
    exit 0
    ;;
  *)
    usage
    exit 99
    ;;
  esac
done


# ----------------------------------------------------------------------------------------------------------------------
# Prepare installation
# ----------------------------------------------------------------------------------------------------------------------

# This trap specifically catches keyboardInterrupt and output a non-zero status before running finish()
trap detectKeyboardInterrupt INT
# Set a trap which, on shell error or shell exit, runs finish()
trap finish EXIT

print info "
*******************************
* Welcome to ADS installation *
*******************************
"

fetch_os_type
check_requirements

# Check to see if the PWD contains the project source files (using `__init__.py` as a proxy for the entire source dir)
# If it exists, then we can reliably access source files (e.g. `requirements-freeze.txt`) from the PWD.
if [[ -e "AxonDeepSeg/__init__.py" ]]; then
  ADS_SOURCE="$PWD"
# If __init__.py isn't present, then the installation script is being run by itself (i.e. without source files).
# So, we need to clone ADS to a TMPDIR to access the source files, and update ADS_SOURCE accordingly.
else
  ADS_SOURCE="$TMP_DIR/axondeepseg"
  echo "Source files not present. Downloading source files (@ $ADS_GIT_REF) to $ADS_SOURCE."
  git clone -b "$ADS_GIT_REF" --single-branch --depth 1 https://github.com/axondeepseg/axondeepseg.git "$ADS_SOURCE"
  # Since we're git cloning into a TMPDIR, this can never be an "in-place" installation, so we force "package" instead.
  ADS_INSTALL_TYPE="package"
fi

# Get installation type if not already specified
if [[ -z "$ADS_INSTALL_TYPE" ]]; then
  # The file 'requirements-freeze.txt` only exists for stable releases
  if [[ -e "$ADS_SOURCE/requirements-freeze.txt" ]]; then
    ADS_INSTALL_TYPE="package"
  # If it doesn't exist, then we can assume that a dev is performing an in-place installation from master
  else
    ADS_INSTALL_TYPE="in-place"
  fi
fi

# Fetch the version of ADS from the source file
ADS_VERSION=$(< "$ADS_SOURCE/AxonDeepSeg/version.txt")

# Define sh files
get_shell_rc_path

# Display install info
echo -e "\nADS version ......... $ADS_VERSION"
echo -e "Installation type ... $ADS_INSTALL_TYPE"
echo -e "Operating system .... $OS ($OSver)"
echo -e "Processor .... $PROCESSOR"
echo -e "Shell config ........ $RC_FILE_PATH"

# if installing from git folder, then becomes default installation folder
if [[ "$ADS_INSTALL_TYPE" == "in-place" ]]; then
  ADS_DIR="$ADS_SOURCE"
else
  ADS_DIR="$HOME/ads_$ADS_VERSION"
fi

# Set install dir
while true; do
  keep_default_path=""
  while [[ ! "$keep_default_path" =~ ^([Yy](es)?|[Nn]o?)$ ]]; do
    print info "ADS will be installed here: [$ADS_DIR]"
    keep_default_path="yes"
    if [ -z "$NONINTERACTIVE" ]; then
      print question "
Do you agree? [y]es/[n]o: "
      read -r keep_default_path
    fi
  done
  if [[ "$keep_default_path" =~ ^[Yy] ]]; then
    # user accepts default path --> exit loop
    break
  fi

  # ASSUMPTION: the rest of these are not guarded by $NONINTERACTIVE because this loop should have been broken already in that case.

  print question "Choose install directory. Warning! Give full path (e.g. /usr/django/ads_v3.0): \n"
  # user enters new path
  read -r new_install

  # Expand ~/
  new_install="${new_install/#\~\//$HOME\/}"
  # Remove trailing /
  new_install="${new_install%/}"

  # Check user-selected path for spaces
  space_regex="[[:space:]]+"
  if [[ $ADS_DIR =~ $space_regex ]]; then
    print info "ERROR: Install directory $ADS_DIR contains spaces.\n\
                ADS uses conda, which does not permit spaces in installation paths.\n\
                More details can be found here: https://github.com/ContinuumIO/anaconda-issues/issues/716"
    continue
  # Avoid horrible bug, like removing /bin if ADS_DIR "/" or $HOME/bin
  elif [[ "$new_install" == "/" ]] || [[ "$HOME" == "${new_install%/}" ]]; then
    print info "Cannot be installed directly in $new_install"
    print info "Please pick a full path"
    continue
  elif [[ -d "$new_install" ]]; then
    # directory exists --> update ADS_DIR and exit loop
    print warning "WARNING: Directory already exists. Files will be overwritten."
    ADS_DIR="$new_install"
    break
  elif [[ ! "$new_install" ]]; then
    # If no input, asking again, and again, and again
    continue
  else
    ADS_DIR="$new_install"
    break
  fi
done

# Create directory
mkdir -p "$ADS_DIR"
# check if directory was created
if [[ -d "$ADS_DIR" ]]; then
  # check write permission
  if [[ ! -w "$ADS_DIR" ]]; then
    die "ERROR: $ADS_DIR exists but does not have write permission."
  fi
else
  die "ERROR: $ADS_DIR cannot be created. Make sure you have write permission."
fi

# Copy files to destination directory
if [[ "$ADS_DIR" != "$ADS_SOURCE" ]]; then
  print info "Copying source files from $ADS_SOURCE to $ADS_DIR"
  cp -vR "$ADS_SOURCE/"* "$ADS_DIR/" | while read -r; do echo -n "."; done
else
  print info "Skipping copy of source files (source and destination folders are the same)"
fi

# Clean old install setup in bin/ if existing
if [[ -x "$ADS_DIR/$BIN_DIR" ]]; then
  print info "Removing ADS softlink from $ADS_DIR/$BIN_DIR"
  find "$ADS_DIR/$BIN_DIR" -type l -name 'axondeepseg_*' -exec rm {} \;
  find "$ADS_DIR/$BIN_DIR" -type l -name 'download_*' -exec rm {} \;
fi
# Remove old conda folder
if [[ -x "$ADS_DIR/$BIN_DIR" ]]; then
  run rm -rf "$ADS_DIR/$CONDA_DIR"
  run mkdir -p "$ADS_DIR/$CONDA_DIR"
fi
# Remove old '.egg-info` folder created by editable installs
if [[ -x "$ADS_DIR"/AxonDeepSeg.egg-info ]]; then
  run rm -rf "$ADS_DIR"/AxonDeepSeg.egg-info
fi

# Go to installation folder
cd "$ADS_DIR"

# Make sure we are in ADS folder (to avoid deleting folder from user)
if [[ ! -f "AxonDeepSeg/__init__.py" ]]; then
  die "ERROR: Cannot cd into ADS folder. ADS_DIR=$ADS_DIR"
fi


# ----------------------------------------------------------------------------------------------------------------------
# Handle RC files / $PATH setting
# ----------------------------------------------------------------------------------------------------------------------

# update PATH environment?
add_to_path=""
while [[ ! "$add_to_path" =~ ^([Yy](es)?|[Nn]o?)$ ]]; do
  add_to_path="yes"
  if [ -z "$NONINTERACTIVE" ]; then
    print question "Do you want to add the axondeepseg_* scripts to your PATH environment? [y]es/[n]o: "
    read -r add_to_path
  fi
done

# Update PATH variables based on Shell type
if [[ $THE_RC == "bash" ]]; then
  DISPLAY_UPDATE_PATH="export PATH=\"$ADS_DIR/$BIN_DIR:\$PATH\""
elif [[ $THE_RC == "csh" ]]; then
  DISPLAY_UPDATE_PATH="setenv PATH \"$ADS_DIR/$BIN_DIR:\$PATH\""
else
  die "This variable is not recognized: THE_RC=$THE_RC"
fi


# ----------------------------------------------------------------------------------------------------------------------
# Install Python
# ----------------------------------------------------------------------------------------------------------------------

# Download miniconda
print info "Downloading Miniconda..."
case $OS in
linux)
  if [[ "$PROCESSOR" == "aarch64" ]] ; then
    download "$TMP_DIR/"miniconda.sh https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-aarch64.sh
  else
    download "$TMP_DIR/"miniconda.sh https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh
  fi
  ;;
osx)
  if [[ "$PROCESSOR" == "arm64" ]] ; then
    download "$TMP_DIR/"miniconda.sh https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-MacOSX-arm64.sh
  else
    download "$TMP_DIR/"miniconda.sh https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-MacOSX-x86_64.sh
  fi
  ;;
esac

# Run conda installer
print info "Installing Miniconda..."
run bash "$TMP_DIR/miniconda.sh" -p "$ADS_DIR/$CONDA_DIR" -b -f

# Workaround for WSL "HTTP 000 Connection Failed" error
# See: https://github.com/conda/conda/issues/9948#issuecomment-909989810
# Syntax explanation: https://stackoverflow.com/a/6085237
find "$ADS_DIR/$CONDA_DIR" -type f -exec touch {} +

# create conda environment
print info "Creating conda environment..."
# NB: We use an absolute path (-p) rather than a relative name (-n) to better isolate the conda environment
"$CONDA_DIR"/bin/conda create -y -p "$ADS_DIR/$CONDA_DIR"/envs/venv_ads python=3.11

# Reapply the touch fix to avoid `pip` connection issues on WSL
find "$ADS_DIR/$CONDA_DIR" -type f -exec touch {} +

# make sure that there is no conflict with local python install by making venv_ads an isolated environment.
# For more information, see:
# * Issue details: https://github.com/spinalcordtoolbox/spinalcordtoolbox/issues/3067
# * Fix details: https://github.com/conda/conda/issues/7173#issuecomment-980496682
echo "include-system-site-packages = false" > "$ADS_DIR/$CONDA_DIR/envs/venv_ads/pyvenv.cfg"

# activate miniconda
# shellcheck disable=SC1091
source "$CONDA_DIR/etc/profile.d/conda.sh"
set +u #disable safeties, for conda is not written to their standard.
conda activate "$ADS_DIR/$CONDA_DIR/envs/venv_ads"
set -u # reactivate safeties

if [[ $OS == linux ]]; then
  # Ensure that packaged GLIBC version is up to date (https://github.com/spinalcordtoolbox/spinalcordtoolbox/issues/3927#issuecomment-1298616317)
  conda install -y -c conda-forge libstdcxx-ng
  # Ensure that libffi isn't linked incorrectly (https://github.com/spinalcordtoolbox/spinalcordtoolbox/issues/3927#issuecomment-1573896770)
  conda install -y -c conda-forge libffi
fi

# Skip pip==21.2 to avoid dependency resolver issue (https://github.com/spinalcordtoolbox/spinalcordtoolbox/issues/3593)
"$CONDA_DIR"/envs/venv_ads/bin/python -m pip install -U "pip!=21.2.*"

## Pre-install numba/llvmlite via pip on Intel macOS.
## llvmlite 0.46+ has no PyPI wheel for x86_64 (last was 0.45.1).
## numba 0.62.1 is the last version requiring llvmlite<0.46.
## We use a constraints file to prevent pip from upgrading them during
## the main install (napari's numba>=0.57.1 would otherwise pull 0.64.0).
if [[ "$OS" == "osx" ]] && [[ "$PROCESSOR" == "x86_64" ]]; then
  print info "Pre-installing numba/llvmlite via pip (Intel macOS workaround)..."
  SYSTEM_VERSION_COMPAT=0 "$CONDA_DIR"/envs/venv_ads/bin/pip install \
    "llvmlite==0.45.1" "numba==0.62.1"
  printf 'llvmlite==0.45.1\nnumba==0.62.1\n' > /tmp/ads_intel_mac_constraints.txt
fi

## Install the axondeepseg into the Conda venv
print info "Installing Python dependencies..."
# We use "--ignore-installed" to preserve the version of `certifi` installed into the conda
# env, which prevents https://github.com/spinalcordtoolbox/spinalcordtoolbox/issues/3609
# We use 'SYSTEM_VERSION_COMPAT=0' to tell pip to report macOS 11 instead of macOS 10.16
# This is necessary in order to install 'macosx_11_0' wheels. See also:
# https://github.com/spinalcordtoolbox/spinalcordtoolbox/issues/4352
print info "Installing Python dependencies..."
if [[ "$OS" == "osx" ]] && [[ "$PROCESSOR" == "x86_64" ]]; then
  SYSTEM_VERSION_COMPAT=0 "$CONDA_DIR"/envs/venv_ads/bin/pip install -e . \
    -c /tmp/ads_intel_mac_constraints.txt && \
    print info "Installing axondeepseg..." && \
    "$CONDA_DIR"/envs/venv_ads/bin/pip install -e . \
      -c /tmp/ads_intel_mac_constraints.txt || die "Failed running pip install: $?"
else
  SYSTEM_VERSION_COMPAT=0 "$CONDA_DIR"/envs/venv_ads/bin/pip install -e . \
    --ignore-installed certifi && \
    print info "Installing axondeepseg..." && \
    "$CONDA_DIR"/envs/venv_ads/bin/pip install -e . || die "Failed running pip install: $?"
fi

print info "All requirements installed!"

## Create launchers for Python scripts
print info "Creating launchers for Python scripts..."
mkdir -p "$ADS_DIR/$BIN_DIR"
for file in "$ADS_DIR/$CONDA_DIR"/envs/venv_ads/bin/*axondeepseg*; do
  cp "$file" "$ADS_DIR/$BIN_DIR/" || die "Problem creating launchers!"
done
for file in "$ADS_DIR/$CONDA_DIR"/envs/venv_ads/bin/*download*; do
  cp "$file" "$ADS_DIR/$BIN_DIR/" || die "Problem creating launchers!"
done
cp "$ADS_DIR/$CONDA_DIR/envs/venv_ads/bin/napari" "$ADS_DIR/$BIN_DIR/ads_napari" || die "Problem creating launchers!"

# Activate the launchers, particularly download_model, download_tests, and axondeepseg_test
export PATH="$ADS_DIR/$BIN_DIR:$PATH"

# ----------------------------------------------------------------------------------------------------------------------
# Download data
# ----------------------------------------------------------------------------------------------------------------------

# Install data
if [[ -n "$NO_DATA_INSTALL" ]]; then
  print warning "WARNING: data files will not be (re)-installed"
else
  # Download data
  print info "Installing data..."
  download_model -d AxonDeepSeg/models
  download_tests
fi

# ----------------------------------------------------------------------------------------------------------------------
# Validate installation
# ----------------------------------------------------------------------------------------------------------------------

# conda is only for a sandbox; users don't use it,
# so neither should our post-install tests
conda deactivate >/dev/null 2>&1

if [[ "$add_to_path" =~ ^[Yy] ]]; then
  edit_shellrc
else
  print info "Not adding $ADS_DIR to \$PATH.
You can always add it later or call ADS functions with full path $ADS_DIR/$BIN_DIR/ads_xxx"
fi

if [[ -n "$NO_INSTALL_VALIDATION" ]]; then
    print warning "WARNING: no checks will be run (installation will not be validated)"
else
  # run axondeepseg_test
  print info "Validate installation..."
  # We run the axondeepseg_test in the TMP_DIR so the tmp.XXX output
  # it creates is cleaned properly
  if axondeepseg_test; then
    if [[ "$add_to_path" =~ ^[Nn] ]]; then
      print info "To use ADS, please update your environment by running:
  $DISPLAY_UPDATE_PATH"
    else
      print info "Open a new Terminal window to load environment variables, or run:
  source $RC_FILE_PATH"
    fi
  print info "AxonDeepSeg was succesfully installed. To open the AxonDeepSeg graphical user interface, type: ads_napari"
  print info "For development use of AxonDeepSeg, activate the virtual environment with: ads_activate"
  print info "Please refer to our documentation on ReadTheDocs for more usage instructions: https://axondeepseg.readthedocs.io/en/latest/"
  else
    die "Installation validation Failed!"
  fi
fi

) 2>&1 | tee install_ads_log.txt
exit "${PIPESTATUS[0]}"
