#!/bin/sh

# This script downloads the 'ghcup' binary into '~/.ghcup/bin/' and then runs an interactive
# installation that lets you choose various options. Below is a list of environment variables
# that affect the installation procedure.

# Main settings:
#   * BOOTSTRAP_HASKELL_NONINTERACTIVE - any nonzero value for noninteractive installation
#   * BOOTSTRAP_HASKELL_NO_UPGRADE - any nonzero value to not trigger the upgrade
#   * BOOTSTRAP_HASKELL_MINIMAL - any nonzero value to only install ghcup
#   * GHCUP_USE_XDG_DIRS - any nonzero value to respect The XDG Base Directory Specification
#   * BOOTSTRAP_HASKELL_VERBOSE - any nonzero value for more verbose installation
#   * BOOTSTRAP_HASKELL_GHC_VERSION - the ghc version to install
#   * BOOTSTRAP_HASKELL_CABAL_VERSION - the cabal version to install
#   * BOOTSTRAP_HASKELL_CABAL_XDG - don't disable the XDG logic (this doesn't force XDG though, because cabal is confusing)
#   * BOOTSTRAP_HASKELL_INSTALL_NO_STACK - disable installation of stack
#   * BOOTSTRAP_HASKELL_INSTALL_NO_STACK_HOOK - disable installation stack ghcup hook
#   * BOOTSTRAP_HASKELL_INSTALL_HLS - whether to install latest hls
#   * BOOTSTRAP_HASKELL_ADJUST_BASHRC - whether to adjust PATH in bashrc (prepend)
#   * BOOTSTRAP_HASKELL_ADJUST_CABAL_CONFIG - whether to adjust mingw paths in cabal.config on windows
#   * BOOTSTRAP_HASKELL_DOWNLOADER - which downloader to use (default: curl)
#   * GHCUP_BASE_URL - the base url for ghcup binary download (use this to overwrite https://downloads.haskell.org/~ghcup with a mirror)
#   * GHCUP_MSYS2_ENV - the msys2 environment to use on windows, see https://www.msys2.org/docs/environments/ (defauts to MINGW64, MINGW32 or CLANGARM64, depending on the architecture)

# License: LGPL-3.0


# safety subshell to avoid executing anything in case this script is not downloaded properly
(

die() {
    if [ -n "${NO_COLOR}" ] ; then
        (>&2 printf "%s\\n" "$1")
    else
        (>&2 printf "\\033[0;31m%s\\033[0m\\n" "$1")
    fi
    exit 2
}

plat="$(uname -s)"
arch=$(uname -m)
ghver="0.1.22.0"
: "${GHCUP_BASE_URL:=https://downloads.haskell.org/~ghcup}"

export GHCUP_SKIP_UPDATE_CHECK=yes
: "${BOOTSTRAP_HASKELL_DOWNLOADER:=curl}"

case "${plat}" in
        MSYS*|MINGW*|CYGWIN*)
			: "${GHCUP_INSTALL_BASE_PREFIX:=/c}"
			GHCUP_DIR=$(cygpath -u "${GHCUP_INSTALL_BASE_PREFIX}/ghcup")
			GHCUP_BIN=$(cygpath -u "${GHCUP_INSTALL_BASE_PREFIX}/ghcup/bin")
			: "${GHCUP_MSYS2:=${GHCUP_DIR}/msys64}"
			;;
		*)
			: "${GHCUP_INSTALL_BASE_PREFIX:=$HOME}"

			if [ -n "${GHCUP_USE_XDG_DIRS}" ] ; then
				GHCUP_DIR=${XDG_DATA_HOME:=$HOME/.local/share}/ghcup
				GHCUP_BIN=${XDG_BIN_HOME:=$HOME/.local/bin}
			else
				GHCUP_DIR=${GHCUP_INSTALL_BASE_PREFIX}/.ghcup
				GHCUP_BIN=${GHCUP_INSTALL_BASE_PREFIX}/.ghcup/bin
			fi
			;;
esac

case "${GHCUP_MSYS2_ENV}" in
    "")
        case "${arch}" in
            x86_64|amd64)
                GHCUP_MSYS2_ENV_DIR="mingw64" ;;
            i*86)
                GHCUP_MSYS2_ENV_DIR="mingw32" ;;
            aarch64|arm64)
                GHCUP_MSYS2_ENV_DIR="clangarm64" ;;
            *) die "Unknown architecture: ${arch}" ;;
        esac
        ;;
    MSYS)
        GHCUP_MSYS2_ENV_DIR="usr" ;;
    UCRT64)
        GHCUP_MSYS2_ENV_DIR="ucrt64" ;;
    CLANG64)
        GHCUP_MSYS2_ENV_DIR="clang64" ;;
    CLANGARM64)
        GHCUP_MSYS2_ENV_DIR="clangarm64" ;;
    CLANG32)
        GHCUP_MSYS2_ENV_DIR="clang32" ;;
    MINGW64)
        GHCUP_MSYS2_ENV_DIR="mingw64" ;;
    MINGW32)
        GHCUP_MSYS2_ENV_DIR="mingw32" ;;
    *)
        die "Invalid value for GHCUP_MSYS2_ENV. Valid values are: MSYS, UCRT64, CLANG64, CLANGARM64, CLANG32, MINGW64, MINGW32" ;;
esac

: "${BOOTSTRAP_HASKELL_GHC_VERSION:=recommended}"
: "${BOOTSTRAP_HASKELL_CABAL_VERSION:=recommended}"



warn() {
    if [ -n "${NO_COLOR}" ] ; then
        printf "%s\\n" "$1"
    else
        case "${plat}" in
                MSYS*|MINGW*|CYGWIN*)
                    # shellcheck disable=SC3037
                    echo -e "\\033[0;35m$1\\033[0m"
                    ;;
                *)
                    printf "\\033[0;35m%s\\033[0m\\n" "$1"
                    ;;
        esac
    fi
}

yellow() {
    if [ -n "${NO_COLOR}" ] ; then
        printf "%s\\n" "$1"
    else
        case "${plat}" in
                MSYS*|MINGW*|CYGWIN*)
                    # shellcheck disable=SC3037
                    echo -e "\\033[0;33m$1\\033[0m"
                    ;;
                *)
                    printf "\\033[0;33m%s\\033[0m\\n" "$1"
                    ;;
        esac
    fi
}

green() {
    if [ -n "${NO_COLOR}" ] ; then
        printf "%s\\n" "$1"
    else
        case "${plat}" in
                MSYS*|MINGW*|CYGWIN*)
                    # shellcheck disable=SC3037
                    echo -e "\\033[0;32m$1\\033[0m"
                    ;;
                *)
                    printf "\\033[0;32m%s\\033[0m\\n" "$1"
                    ;;
        esac
    fi
}

edo() {
    "$@" || die "\"$*\" failed!"
}

eghcup_raw() {
	"${GHCUP_BIN}/ghcup" "$@" || die "\"ghcup $*\" failed!"
}

eghcup() {
	_eghcup "$@"
}

_eghcup() {
	if [ -n "${BOOTSTRAP_HASKELL_YAML}" ] ; then
		args="-s ${BOOTSTRAP_HASKELL_YAML} --metadata-fetching-mode=Strict"
    else
		args="--metadata-fetching-mode=Strict"
	fi
    if [ -z "${BOOTSTRAP_HASKELL_VERBOSE}" ] ; then
        # shellcheck disable=SC2086
        "${GHCUP_BIN}/ghcup" ${args} "$@" || die "\"ghcup ${args} $*\" failed!"
    else
        # shellcheck disable=SC2086
        "${GHCUP_BIN}/ghcup" ${args} --verbose "$@" || die "\"ghcup ${args} --verbose $*\" failed!"
    fi
}

_ecabal() {
    # shellcheck disable=SC2317
    if [ -n "${CABAL_BIN}" ] ; then
        "${CABAL_BIN}" "$@"
    else
        # shellcheck disable=SC2086
        "${GHCUP_BIN}/cabal" "$@"
    fi
}

ecabal() {
	_ecabal "$@" || die "\"cabal $*\" failed!"
}

_done() {
	echo
	echo "==============================================================================="
	case "${plat}" in
   			MSYS*|MINGW*|CYGWIN*)
				green
				green "All done!"
				green
				green "In a new powershell or cmd.exe session, now you can..."
				green
				green "Start a simple repl via:"
				green "  ghci"
				green
				green "Start a new haskell project in the current directory via:"
				green "  cabal init --interactive"
				green
				green "To install other GHC versions and tools, run:"
				green "  ghcup tui"
				green
				green "To install system libraries and update msys2/mingw64,"
				green "open the \"Mingw haskell shell\""
				green "and the \"Mingw package management docs\""
				green "desktop shortcuts."
				green
				green "If you are new to Haskell, check out https://www.haskell.org/ghcup/steps/"
				;;
			*)
				green
				green "All done!"
				green
				green "To start a simple repl, run:"
				green "  ghci"
				green
				green "To start a new haskell project in the current directory, run:"
				green "  cabal init --interactive"
				green
				green "To install other GHC versions and tools, run:"
				green "  ghcup tui"
				green
				green "If you are new to Haskell, check out https://www.haskell.org/ghcup/steps/"
				;;

	esac


	exit 0
}

# @FUNCTION: posix_realpath
# @USAGE: <file>
# @DESCRIPTION:
# Portably gets the realpath and prints it to stdout.
# This was initially inspired by
#   https://gist.github.com/tvlooy/cbfbdb111a4ebad8b93e
#   and
#   https://stackoverflow.com/a/246128
#
# If the file does not exist, just prints it appended to the current directory.
# @STDOUT: realpath of the given file
posix_realpath() {
    [ -z "$1" ] && die "Internal error: no argument given to posix_realpath"
    current_loop=0
    max_loops=50
    mysource=$1
    # readlink and '[ -h $path ]' behave different wrt '/sbin/' and '/sbin', so we strip it
    mysource=${mysource%/}
    [ -z "${mysource}" ] && mysource=$1

    while [ -h "${mysource}" ]; do
        current_loop=$((current_loop+1))
        mydir="$( cd -P "$( dirname "${mysource}" )" > /dev/null 2>&1 && pwd )"
        mysource="$(readlink "${mysource}")"
        [ "${mysource%"${mysource#?}"}"x != '/x' ] && mysource="${mydir%/}/${mysource}"

        if [ ${current_loop} -gt ${max_loops} ] ; then
            (>&2 echo "${1}: Too many levels of symbolic links")
			echo "$1"
            return
        fi
    done
    mydir="$( cd -P "$( dirname "${mysource}" )" > /dev/null 2>&1 && pwd )"

    # TODO: better distinguish between "does not exist" and "permission denied"
    if [ -z "${mydir}" ] ; then
        (>&2 echo "${1}: Permission denied")
		echo "$(pwd)/$1"
    else
        echo "${mydir%/}/$(basename "${mysource}")"
    fi

    unset current_loop max_loops mysource mydir
}

download_ghcup() {

    case "${plat}" in
        "linux"|"Linux")
			case "${arch}" in
				x86_64|amd64)
					# we could be in a 32bit docker container, in which
					# case uname doesn't give us what we want
					if [ "$(getconf LONG_BIT)" = "32" ] ; then
						_url=${GHCUP_BASE_URL}/${ghver}/i386-linux-ghcup-${ghver}
					elif [ "$(getconf LONG_BIT)" = "64" ] ; then
						_url=${GHCUP_BASE_URL}/${ghver}/x86_64-linux-ghcup-${ghver}
					else
						die "Unknown long bit size: $(getconf LONG_BIT)"
					fi
					;;
				i*86)
					_url=${GHCUP_BASE_URL}/${ghver}/i386-linux-ghcup-${ghver}
					;;
				armv7*|*armv8l*)
					_url=${GHCUP_BASE_URL}/${ghver}/armv7-linux-ghcup-${ghver}
					;;
				aarch64|arm64)
					# we could be in a 32bit docker container, in which
					# case uname doesn't give us what we want
					if [ "$(getconf LONG_BIT)" = "32" ] ; then
						_url=${GHCUP_BASE_URL}/${ghver}/armv7-linux-ghcup-${ghver}
					elif [ "$(getconf LONG_BIT)" = "64" ] ; then
						_url=${GHCUP_BASE_URL}/${ghver}/aarch64-linux-ghcup-${ghver}
					else
						die "Unknown long bit size: $(getconf LONG_BIT)"
					fi
					;;
				*) die "Unknown architecture: ${arch}"
					;;
			esac
			;;
        "FreeBSD"|"freebsd")
			case "${arch}" in
				x86_64|amd64)
					;;
				i*86)
					die "i386 currently not supported!"
					;;
				*) die "Unknown architecture: ${arch}"
					;;
			esac
			_url=${GHCUP_BASE_URL}/${ghver}/x86_64-portbld-freebsd-ghcup-${ghver}
            ;;
        "Darwin"|"darwin")
			case "${arch}" in
				x86_64|amd64)
					_url=${GHCUP_BASE_URL}/${ghver}/x86_64-apple-darwin-ghcup-${ghver}
					;;
				aarch64|arm64|armv8l)
					_url=${GHCUP_BASE_URL}/${ghver}/aarch64-apple-darwin-ghcup-${ghver}
					;;
				i*86)
					die "i386 currently not supported!"
					;;
				*) die "Unknown architecture: ${arch}"
					;;
			esac
			;;
        MSYS*|MINGW*|CYGWIN*)
			case "${arch}" in
				x86_64|amd64)
					_url=${GHCUP_BASE_URL}/${ghver}/x86_64-mingw64-ghcup-${ghver}.exe
					;;
				*) die "Unknown architecture: ${arch}"
					;;
			esac
			;;
        *) die "Unknown platform: ${plat}"
			;;
    esac
    case "${plat}" in
        MSYS*|MINGW*|CYGWIN*)
            case "${BOOTSTRAP_HASKELL_DOWNLOADER}" in
                "curl")
	                # shellcheck disable=SC2086
                    edo curl -Lf ${GHCUP_CURL_OPTS} "${_url}" > "${GHCUP_BIN}"/ghcup.exe
                    ;;
                "wget")
	                # shellcheck disable=SC2086
                    edo wget -O /dev/stdout ${GHCUP_WGET_OPTS} "${_url}" > "${GHCUP_BIN}"/ghcup.exe
                    ;;
                *)
                    die "Unknown downloader: ${BOOTSTRAP_HASKELL_DOWNLOADER}"
                    ;;
            esac
			edo chmod +x "${GHCUP_BIN}"/ghcup.exe
			;;
		*)
            case "${BOOTSTRAP_HASKELL_DOWNLOADER}" in
                "curl")
	                # shellcheck disable=SC2086
                    edo curl -Lf ${GHCUP_CURL_OPTS} "${_url}" > "${GHCUP_BIN}"/ghcup
                    ;;
                "wget")
	                # shellcheck disable=SC2086
                    edo wget -O /dev/stdout ${GHCUP_WGET_OPTS} "${_url}" > "${GHCUP_BIN}"/ghcup
                    ;;
                *)
                    die "Unknown downloader: ${BOOTSTRAP_HASKELL_DOWNLOADER}"
                    ;;
            esac
			edo chmod +x "${GHCUP_BIN}"/ghcup
			;;
	esac

	edo mkdir -p "${GHCUP_DIR}"

	# we may overwrite this in adjust_bashrc
	cat <<-EOF > "${GHCUP_DIR}"/env || die "Failed to create env file"
		case ":\$PATH:" in
		    *:"${GHCUP_BIN}":*)
		        ;;
		    *)
		        export PATH="${GHCUP_BIN}:\$PATH"
		        ;;
		esac
		case ":\$PATH:" in
		    *:"\$HOME/.cabal/bin":*)
		        ;;
		    *)
		        export PATH="\$HOME/.cabal/bin:\$PATH"
		        ;;
		esac
		EOF

	# shellcheck disable=SC1090
    edo . "${GHCUP_DIR}"/env
    case "${BOOTSTRAP_HASKELL_DOWNLOADER}" in
        "curl")
            eghcup_raw config set downloader Curl
            ;;
        "wget")
            eghcup_raw config set downloader Wget
            ;;
        *)
            die "Unknown downloader: ${BOOTSTRAP_HASKELL_DOWNLOADER}"
            ;;
    esac
    eghcup upgrade
}

# Figures out the users login shell and sets
# GHCUP_PROFILE_FILE and MY_SHELL variables.
find_shell() {
	case $SHELL in
		*/zsh) # login shell is zsh
			if [ -n "$ZDOTDIR" ]; then
				GHCUP_PROFILE_FILE="$ZDOTDIR/.zshrc"
			else
				GHCUP_PROFILE_FILE="$HOME/.zshrc"
			fi
			MY_SHELL="zsh" ;;
		*/bash) # login shell is bash
			GHCUP_PROFILE_FILE="$HOME/.bashrc"
			MY_SHELL="bash" ;;
		*/sh) # login shell is sh, but might be a symlink to bash or zsh
			if [ -n "${BASH}" ] ; then
				GHCUP_PROFILE_FILE="$HOME/.bashrc"
				MY_SHELL="bash"
			elif [ -n "${ZSH_VERSION}" ] ; then
				GHCUP_PROFILE_FILE="$HOME/.zshrc"
				MY_SHELL="zsh"
			else
				return
			fi
			;;
		*/fish) # login shell is fish
			GHCUP_PROFILE_FILE="$HOME/.config/fish/config.fish"
			MY_SHELL="fish" ;;
		*) return ;;
	esac
}

# Ask user if they want to adjust the bashrc.
ask_bashrc() {
	if [ -n "${BOOTSTRAP_HASKELL_ADJUST_BASHRC}" ] ; then
		return 1
	elif [ -z "${MY_SHELL}" ] ; then
		return 0
	fi

	while true; do
		if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
			echo "-------------------------------------------------------------------------------"

			warn ""
			warn "Detected ${MY_SHELL} shell on your system..."
			warn "Do you want ghcup to automatically add the required PATH variable to \"${GHCUP_PROFILE_FILE}\"?"
			warn ""
			warn "[P] Yes, prepend  [A] Yes, append  [N] No  [?] Help (default is \"P\")."
			warn ""

			read -r bashrc_answer </dev/tty
		else
			return 0
		fi
		case $bashrc_answer in
			[Pp]* | "")
				return 1
				;;
			[Aa]*)
				return 2
				;;
			[Nn]*)
				return 0;;
			*)
				echo "Possible choices are:"
				echo
				echo "P - Yes, prepend to PATH, taking precedence (default)"
				echo "A - Yes, append to PATH"
				echo "N - No, don't mess with my configuration"
				echo
				echo "Please make your choice and press ENTER."
				;;
		esac
	done

	unset bashrc_answer
}

# Needs 'find_shell' to be called beforehand.
adjust_bashrc() {
	case $1 in
		1)
			cat <<-EOF > "${GHCUP_DIR}"/env || die "Failed to create env file"
				case ":\$PATH:" in
				    *:"${GHCUP_BIN}":*)
				        ;;
				    *)
				        export PATH="${GHCUP_BIN}:\$PATH"
				        ;;
				esac
				case ":\$PATH:" in
				    *:"\$HOME/.cabal/bin":*)
				        ;;
				    *)
				        export PATH="\$HOME/.cabal/bin:\$PATH"
				        ;;
				esac
				EOF
			;;
		2)
			cat <<-EOF > "${GHCUP_DIR}"/env || die "Failed to create env file"
				case ":\$PATH:" in
				    *:"\$HOME/.cabal/bin":*)
				        ;;
				    *)
				        export PATH="\$PATH:\$HOME/.cabal/bin"
				        ;;
				esac
				case ":\$PATH:" in
				    *:"${GHCUP_BIN}":*)
				        ;;
				    *)
				        export PATH="\$PATH:${GHCUP_BIN}"
				        ;;
				esac
				EOF
			;;
		*) ;;
	esac

	case $1 in
		1 | 2)
			case $MY_SHELL in
				"")
					warn_path "Couldn't figure out login shell!"
					return
					;;
				fish)
					mkdir -p "${GHCUP_PROFILE_FILE%/*}"
					sed -i -e '/# ghcup-env$/d' "$(posix_realpath "${GHCUP_PROFILE_FILE}")"
					case $1 in
						1)
							printf "\n%s" "set -q GHCUP_INSTALL_BASE_PREFIX[1]; or set GHCUP_INSTALL_BASE_PREFIX \$HOME ; set -gx PATH \$HOME/.cabal/bin $GHCUP_BIN \$PATH # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
							;;
						2)
							printf "\n%s" "set -q GHCUP_INSTALL_BASE_PREFIX[1]; or set GHCUP_INSTALL_BASE_PREFIX \$HOME ; set -gx PATH \$HOME/.cabal/bin \$PATH $GHCUP_BIN # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
							;;
					esac
					;;
				bash)
					sed -i -e '/# ghcup-env$/d' "$(posix_realpath "${GHCUP_PROFILE_FILE}")"
					printf "\n%s" "[ -f \"${GHCUP_DIR}/env\" ] && . \"${GHCUP_DIR}/env\" # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
					case "${plat}" in
						"Darwin"|"darwin")
							if ! grep -q "ghcup-env" "${HOME}/.bash_profile" ; then
								printf "\n%s" "[[ -f ~/.bashrc ]] && . ~/.bashrc # ghcup-env" >> "${HOME}/.bash_profile"
							fi
							;;
   						MSYS*|MINGW*|CYGWIN*)
							if [ ! -e "${HOME}/.bash_profile" ] ; then
								echo '# generated by ghcup' > "${HOME}/.bash_profile"
								echo 'test -f ~/.profile && . ~/.profile' >> "${HOME}/.bash_profile"
								echo 'test -f ~/.bashrc && . ~/.bashrc' >> "${HOME}/.bash_profile"
							fi
							;;
					esac
					;;

				zsh)
					sed -i -e '/# ghcup-env$/d' "$(posix_realpath "${GHCUP_PROFILE_FILE}")"
					printf "\n%s" "[ -f \"${GHCUP_DIR}/env\" ] && . \"${GHCUP_DIR}/env\" # ghcup-env" >> "${GHCUP_PROFILE_FILE}"
					;;
			esac
            if [ -e "$HOME/.profile" ] ; then
					sed -i -e '/# ghcup-env$/d' "$(posix_realpath "$HOME/.profile")"
					printf "\n%s" "[ -f \"${GHCUP_DIR}/env\" ] && . \"${GHCUP_DIR}/env\" # ghcup-env" >> "$HOME/.profile"
            fi
			echo
			echo "==============================================================================="
			echo
			warn "OK! ${GHCUP_PROFILE_FILE} has been modified. Restart your terminal for the changes to take effect,"
			warn "or type \". ${GHCUP_DIR}/env\" to apply them in your current terminal session."
			return
			;;
		*)
			warn_path
			;;
	esac
}

warn_path() {
	echo
	echo "==============================================================================="
	echo
	[ -n "$1" ] && warn "$1"
	yellow "In order to run ghc and cabal, you need to adjust your PATH variable."
	yellow "To do so, you may want to run 'source $GHCUP_DIR/env' in your current terminal"
	yellow "session as well as your shell configuration (e.g. ~/.bashrc)."

}

adjust_cabal_config() {
    if [ -n "${CABAL_DIR}" ] ; then
        cabal_bin="${CABAL_DIR}/bin"
    else
        cabal_bin="$HOME/AppData/Roaming/cabal/bin"
    fi
    ecabal user-config -a "extra-prog-path: $(cygpath -w "$GHCUP_BIN"), $(cygpath -w "$cabal_bin"), $(cygpath -w "$GHCUP_MSYS2"/${GHCUP_MSYS2_ENV_DIR}/bin), $(cygpath -w "$GHCUP_MSYS2"/usr/bin)" -a "extra-include-dirs: $(cygpath -w "$GHCUP_MSYS2"/${GHCUP_MSYS2_ENV_DIR}/include)" -a "extra-lib-dirs: $(cygpath -w "$GHCUP_MSYS2"/${GHCUP_MSYS2_ENV_DIR}/lib)" -f init
}

ask_cabal_config_init() {
	case "${plat}" in
   			MSYS*|MINGW*|CYGWIN*)
				if [ -n "${BOOTSTRAP_HASKELL_ADJUST_CABAL_CONFIG}" ] ; then
					return 1
				fi

				if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
					echo "-------------------------------------------------------------------------------"
					warn "Create an initial cabal.config including relevant msys2 paths (recommended)?"
					warn "[Y] Yes  [N] No  [?] Help (default is \"Y\")."
					echo
					while true; do
						read -r mingw_answer </dev/tty

						case $mingw_answer in
							[Yy]* | "")
								return 1 ;;
							[Nn]*)
								return 0 ;;
							*)
								echo "Possible choices are:"
								echo
								echo "Y - Yes, create a cabal.config with pre-set paths to msys2/mingw64 (default)"
								echo "N - No, leave the current/default cabal config untouched"
								echo
								echo "Please make your choice and press ENTER."
								;;
						esac
					done
				else
					return 0
				fi
				;;
	esac

	unset mingw_answer

    return 0
}

do_cabal_config_init() {
	case "${plat}" in
   			MSYS*|MINGW*|CYGWIN*)
		case $1 in
			1)
				adjust_cabal_config
				;;
			0)
				warn "Make sure that your global cabal.config references the correct mingw64 paths (extra-prog-path, extra-include-dirs and extra-lib-dirs)."
				warn "And set the environment variable GHCUP_MSYS2 to the root path of your msys2 installation."
				sleep 5
				return ;;
			*) ;;
		esac
	esac
}

ask_hls() {
	if [ -n "${BOOTSTRAP_HASKELL_INSTALL_HLS}" ] ; then
		return 1
	fi

	if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
		echo "-------------------------------------------------------------------------------"

		warn "Do you want to install haskell-language-server (HLS)?"
		warn "HLS is a language-server that provides IDE-like functionality"
		warn "and can integrate with different editors, such as Vim, Emacs, VS Code, Atom, ..."
		warn "Also see https://haskell-language-server.readthedocs.io/en/stable/"
		warn ""
		warn "[Y] Yes  [N] No  [?] Help (default is \"N\")."
		warn ""

		while true; do
			read -r hls_answer </dev/tty

			case $hls_answer in
				[Yy]*)
					return 1
					;;
				[Nn]* | "")
					return 0
					;;
				*)
					echo "Possible choices are:"
					echo
					echo "Y - Yes, install the haskell-language-server"
					echo "N - No, don't install anything more (default)"
					echo
					echo "Please make your choice and press ENTER."
					;;
			esac
		done
	else
		return 0
	fi

	unset hls_answer
}

ask_stack() {
    if [ -n "${BOOTSTRAP_HASKELL_INSTALL_NO_STACK}" ] ; then
		return 0
    elif [ -n "${BOOTSTRAP_HASKELL_INSTALL_NO_STACK_HOOK}" ] ; then
		return 1
	fi

	if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
		echo "-------------------------------------------------------------------------------"

		warn "Do you want to enable better integration of stack with GHCup?"
        warn "This means that stack won't install its own GHC versions, but uses GHCup's."
        warn "For more information see:"
        warn "  https://docs.haskellstack.org/en/stable/yaml_configuration/#ghc-installation-customisation-experimental"
        warn "If you want to keep stacks vanilla behavior, answer 'No'."
		warn ""
		warn "[Y] Yes  [N] No  [?] Help (default is \"Y\")."
		warn ""

		while true; do
			read -r stack_answer </dev/tty

			case $stack_answer in
				[Yy]* | "")
					return 2 ;;
				[Nn]*)
					return 1 ;;
				*)
					echo "Possible choices are:"
					echo
                    echo "Y - Yes, enable better integration (default)"
					echo "N - No, keep stacks vanilla behavior"
					echo
					echo "Please make your choice and press ENTER."
					;;
			esac
		done
	else
		return 2
	fi

	unset stack_answer
}

find_stack_root() {
    if [ -n "${STACK_ROOT}" ] ; then
        echo "${STACK_ROOT}"
    elif [ -n "${STACK_XDG}" ] ; then
        echo "${XDG_DATA_HOME:-$HOME/.local/share}/stack"
    else
        echo "${HOME}/.stack"
    fi
}

find_shell


echo
echo "Welcome to Haskell!"
echo
echo "This script can download and install the following binaries:"
echo "  * ghcup - The Haskell toolchain installer"
echo "  * ghc   - The Glasgow Haskell Compiler"
echo "  * cabal - The Cabal build tool for managing Haskell software"
echo "  * stack - A cross-platform program for developing Haskell projects (similar to cabal)"
echo "  * hls   - (optional) A language server for developers to integrate with their editor/IDE"
echo
if [ -z "${GHCUP_USE_XDG_DIRS}" ] ; then
	echo "ghcup installs only into the following directory,"
    echo "which can be removed anytime:"
	case "${plat}" in
   			MSYS*|MINGW*|CYGWIN*)
				echo "  $(cygpath -w "$GHCUP_DIR")"
				;;
			*)
				echo "  $GHCUP_DIR"
				;;
	esac
else
	echo "ghcup installs into XDG directories as long as"
    echo "'GHCUP_USE_XDG_DIRS' is set."
fi
echo

if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
    warn "Press ENTER to proceed or ctrl-c to abort."
    warn "Note that this script can be re-run at any given time."
    # Wait for user input to continue.
    # shellcheck disable=SC2034
    read -r answer </dev/tty
fi

ask_bashrc
ask_bashrc_answer=$?
ask_cabal_config_init
ask_cabal_config_init_answer=$?
if [ -z "${BOOTSTRAP_HASKELL_MINIMAL}" ] ; then
	ask_hls
	ask_hls_answer=$?
	ask_stack
	ask_stack_answer=$?
fi

edo mkdir -p "${GHCUP_BIN}"

if command -V "ghcup" >/dev/null 2>&1 ; then
    if [ -z "${BOOTSTRAP_HASKELL_NO_UPGRADE}" ] ; then
        ( _eghcup upgrade ) || download_ghcup
    fi
else
	download_ghcup
fi

echo
if [ -n "${BOOTSTRAP_HASKELL_YAML}" ] ; then (>&2 ghcup -s "${BOOTSTRAP_HASKELL_YAML}" tool-requirements) ; else (>&2 ghcup tool-requirements) ; fi
echo

if [ -z "${BOOTSTRAP_HASKELL_NONINTERACTIVE}" ] ; then
    warn "Press ENTER to proceed or ctrl-c to abort."
    warn "Installation may take a while."
    echo

    # Wait for user input to continue.
    # shellcheck disable=SC2034
    read -r answer </dev/tty
fi

if [ -z "${BOOTSTRAP_HASKELL_MINIMAL}" ] ; then
	eghcup --cache install ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"

	eghcup set ghc "${BOOTSTRAP_HASKELL_GHC_VERSION}"
	eghcup --cache install cabal "${BOOTSTRAP_HASKELL_CABAL_VERSION}"

	do_cabal_config_init $ask_cabal_config_init_answer

    if [ -z "${BOOTSTRAP_HASKELL_CABAL_XDG}" ] ; then
        # disable XDG if we can
        if [ -e "${XDG_CONFIG_HOME:-"$HOME/.config"}/cabal" ] || [ -n "${CABAL_DIR}" ] || [ -n "${CABAL_CONFIG}" ] ; then
            :
        else
            edo mkdir -p "${HOME}/.cabal"
        fi
    fi

	edo cabal update --ignore-project
else # don't install ghc and cabal
	case "${plat}" in
   			MSYS*|MINGW*|CYGWIN*)
				# need to bootstrap cabal to initialize config on windows
				# we'll remove it afterwards
				tmp_dir="$(mktemp -d)"
				eghcup --cache install cabal -i "${tmp_dir}" "${BOOTSTRAP_HASKELL_CABAL_VERSION}"
				CABAL_BIN="${tmp_dir}/cabal" do_cabal_config_init $ask_cabal_config_init_answer
				rm "${tmp_dir}/cabal"
				unset tmp_dir
				;;
			*)
				;;
	esac
fi

case $ask_hls_answer in
	1)
        (_eghcup --cache install hls) || warn "HLS installation failed, continuing anyway"
		;;
	*) ;;
esac

case $ask_stack_answer in
	1)
        (_eghcup --cache install stack) || die "Stack installation failed"
		;;
	2)
        (_eghcup --cache install stack) || die "Stack installation failed"
        stack_root="$(find_stack_root)"
        edo mkdir -p "${stack_root}"/hooks
        hook_exe="${stack_root}"/hooks/ghc-install.sh
        hook_url="https://www.haskell.org/ghcup/sh/hooks/stack/ghc-install.sh"

        if [ -e "${hook_exe}" ] ; then
            warn "$hook_exe already exists, skipping hook installation."
            warn "If you want to reinstall the hook, delete it manually and re-run"
            warn "this script!"
        else
            case "${BOOTSTRAP_HASKELL_DOWNLOADER}" in
                "curl")
                    # shellcheck disable=SC2086
                    edo curl -Lf ${GHCUP_CURL_OPTS} "${hook_url}" > "${hook_exe}"
                    ;;
                "wget")
                    # shellcheck disable=SC2086
                    edo wget -O /dev/stdout ${GHCUP_WGET_OPTS} "${hook_url}" > "${hook_exe}"
                    ;;
                *)
                    die "Unknown downloader: ${BOOTSTRAP_HASKELL_DOWNLOADER}"
                    ;;
            esac
            edo chmod +x "${hook_exe}"
        fi

		;;
	*) ;;
esac


adjust_bashrc $ask_bashrc_answer


_done

)

# vim: tabstop=4 shiftwidth=4 expandtab