#!/usr/bin/env bash

set -e

function help() {
	cat <<EOF
usage: configure-vs-code [options] [vs-code-args]

Configure VS Code for use with Posit Workbench.

Examples
   configure-vs-code
   configure-vs-code --version 2025.04-b13166
   configure-vs-code --overwrite no
   configure-vs-code --overwrite yes --extensions-dir=/opt/code-server/extensions

Positional Arguments
   vs-code-args
         All additional arguments given to the script will be added to the args entry in
         vscode.conf and passed to the VS Code binary when a session is started.

         --extensions-dir=<path>
               Specifies a global vscode extensions directory. If specified then
               this script will also install the Posit Workbench VS Code extension.

Options
   --overwrite <yes|no|prompt>
         What to do with existing configuration files. The default is "prompt".

            yes
                  overwrite existing files without prompting
            no
                  don't overwrite existing files, no prompt
            prompt
                  prompt for each existing file

   --version <version>
         Install a specific version of PWB Code Server, overwriting the version installed with the product.

   -h, --help
         Show this help.

EOF
}

overwrite=prompt

while [ ! -z "$1" ]; do
   case "$1" in
      --overwrite)
            overwrite="$2"
            shift
            ;;
      --version)
            new_version="$2";
            if [[ ! "$new_version" =~ ^[0-9]+\.[0-9]+\-[a-z0-9]+$ ]]; then
               echo "Invalid version: $new_version"
               exit 1
            fi
            shift
            ;;
      --help|-h)
            help
            exit 0
            ;;
      *)
         # pass all subsequent options through to vscode
         break
         ;;
   esac
   shift
done

case "$overwrite" in
    yes)
        ;;
    no)
        ;;
    prompt)
        ;;
    *)
        echo "Error: --overwrite=${overwrite} is not valid." >&2
        exit 1
        ;;
esac

# determine vscode config file
configDirs="$XDG_CONFIG_DIRS:/etc"
origIFS=IFS
IFS=':'; read -ra configDirList <<< "$configDirs"
for configDir in configDirList[@]
do
  if test -e "$configDir/rstudio/vscode.conf"
  then
    configFile="$configDir/rstudio/vscode.conf"
    break
  fi
done
IFS=$origIFS
if [[ $configFile == "" ]]
then
   configFile="/etc/rstudio/vscode.conf"
fi

INSTALL_BIN_DIR=/usr/lib/rstudio-server/bin
CODE_SERVER_DIR=pwb-code-server
VSCODE_VERSION=${new_version:-2025.08-b16541}


# Check for existing version; if found and version matches, we're done; otherwise
# delete existing folder before reinstalling
if [ -d ${INSTALL_BIN_DIR}/${CODE_SERVER_DIR} ]; then
   if grep -q "${VSCODE_VERSION}" ${INSTALL_BIN_DIR}/${CODE_SERVER_DIR}/pwb-version; then
      echo "PWB VS Code version ${VSCODE_VERSION} already installed"
   fi
fi

# download from CDN
echo "Downloading Posit Workbench Code Server..."

CDN=https://cdn.posit.co/pwb-components
if [[ $(uname -m) == "aarch64" ]]; then
   ARCH=arm64
else
   ARCH=x86_64
fi
VSCODE_ARCHIVE="${CODE_SERVER_DIR}-${VSCODE_VERSION}-${ARCH}.tar.gz"

if ! curl -fL "${CDN}/${CODE_SERVER_DIR}/${VSCODE_ARCHIVE}" -o "/tmp/${VSCODE_ARCHIVE}"; then
   echo "Failed to download ${CDN}/${CODE_SERVER_DIR}/${VSCODE_ARCHIVE}"
   exit 1
else
   echo "Removing existing PWB VS Code version at ${INSTALL_BIN_DIR}/${CODE_SERVER_DIR}"
   rm -rf "${INSTALL_BIN_DIR:?}/${CODE_SERVER_DIR:?}"
fi
mkdir -p "${INSTALL_BIN_DIR}/${CODE_SERVER_DIR}"

tar zxf "/tmp/${VSCODE_ARCHIVE}" --strip 1 -C "${INSTALL_BIN_DIR}/${CODE_SERVER_DIR}"
rm "/tmp/${VSCODE_ARCHIVE}"
echo "${CODE_SERVER_DIR} (${VSCODE_VERSION}-${ARCH}) copied to ${INSTALL_BIN_DIR}/${CODE_SERVER_DIR}"

# update vs code / RSP configuration
GENERATE_VSCODE_CONF=true
if [ -f $configFile ]
then
   if [ $overwrite = "prompt" ]
   then
      cs_exe=$(grep "^[ \t]*exe" $configFile | sed 's/.*\(exe=\)\(.[^ ]*\).*/\2/')
      if [ -z "$cs_exe" ]; then
         cs_exe="${INSTALL_BIN_DIR}/${CODE_SERVER_DIR}/bin/code-server"
      fi
      promptText1="The VSCode configuration file $configFile already exists"
      if [[ $cs_exe != */rstudio-server/bin/*code-server* ]]; then
         promptText2=" and is configured to use an older version of VS Code - do you wish to regenerate it to use the latest supported version (y or n)? "
      else
         promptText2=" - do you wish to regenerate it (y or n)?"
      fi
      promptText="${promptText1}${promptText2}"
      while true; do
         read -p "${promptText} " yn
         case $yn in
            [Yy]* ) GENERATE_VSCODE_CONF=true; break;;
            [Nn]* ) GENERATE_VSCODE_CONF=false; break;;
            * ) echo "Invalid input - please input either yes or no";;
         esac
      done
   elif [ $overwrite = "no" ]
   then
      echo "${configFile} already exists, skipping"
      GENERATE_VSCODE_CONF=false
   fi
fi

if [ "$GENERATE_VSCODE_CONF" = true ]; then
   configContents="enabled=1
exe=/usr/lib/rstudio-server/bin/${CODE_SERVER_DIR}/bin/code-server
args=--host=0.0.0.0 ${@}"

   echo "$configContents" > $configFile
   chmod 644 $configFile
   echo "$configFile generated"

   # Don't need to tell admin to restart server during installation; the installation itself
   # takes care of that. The postinst script invokes this script with "--overwrite no", so use
   # that as a hint that we're in the middle of an install vs. the script being run by an
   # administrator directly.
   if [ "$overwrite" != "no" ]; then
      DISPLAY_RESTART_HINT=true
   fi
else
   # update config to remove outdated code-server flag we set prior to Juliet Rose
   sed -iE "s|--disable-updates[ ]\?||" $configFile

   # code-server move the executable to /bin in 3.3.0
   # in case we are updating code-server, determine if the exe needs to be updated
   cs_exe=$(grep exe $configFile | sed 's/.*\(exe=\)\(.[^ ]*\).*/\2/')
   if [[ $cs_exe != */bin/* ]]
   then
      orig_cs_exe="$cs_exe"
      cs_exe=$(dirname $cs_exe)/bin/code-server
      sed -i "s|$orig_cs_exe|$cs_exe|" $configFile
   fi
fi

GENERATE_VSCODE_USER_SETTINGS=true
if [ -f "/etc/rstudio/vscode-user-settings.json" ]
then
   if [ $overwrite = "prompt" ]
   then
      while true; do
         read -p "The VSCode user settings json configuration file /etc/rstudio/vscode-user-settings.json already exists - do you wish to regenerate it (y or n)? " yn
         case $yn in
            [Yy]* ) GENERATE_VSCODE_USER_SETTINGS=true; break;;
            [Nn]* ) GENERATE_VSCODE_USER_SETTINGS=false; break;;
            * ) echo "Invalid input - please input either yes or no";;
         esac
      done
   elif [ $overwrite = "no" ]
   then
      echo "/etc/rstudio/vscode-user-settings.json already exists, skipping"
      GENERATE_VSCODE_USER_SETTINGS=false
   fi
fi

if [ "$GENERATE_VSCODE_USER_SETTINGS" = true ]; then
   userSettingsContents="{
      \"terminal.integrated.defaultProfile.linux\": \"$SHELL\",
      \"extensions.autoUpdate\": false,
      \"extensions.autoCheckUpdates\": false,
      \"quarto.path\": \"/usr/lib/rstudio-server/bin/quarto/bin/quarto\"
}"

   echo "$userSettingsContents" > /etc/rstudio/vscode-user-settings.json
   chmod 644 /etc/rstudio/vscode-user-settings.json
   echo "/etc/rstudio/vscode-user-settings.json generated"
fi

if [[ "${@}" =~ "--extensions-dir" ]]
then
   rstudio-server install-vs-code-ext
fi

if [ "$DISPLAY_RESTART_HINT" = true ]; then
   echo "NOTE: New VS Code settings will not take effect until Posit Workbench is restarted (e.g. rstudio-server restart)."
fi
