#!/usr/bin/env bash
# Copyright (c) 2023-present JoliCode
#
# Castor installer: this file is part of the Castor project.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is furnished
# to do so, subject to the following conditions:

# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
set -euo pipefail

CASTOR_EXECUTABLE="castor"
CASTOR_TMP_NAME="$CASTOR_EXECUTABLE-"$(date +"%s")
CASTOR_NAME="🦫  Castor"
CASTOR_DOWNLOAD_URL_PATTERN="https://github.com/jolicode/castor/releases/latest/download/castor.~platform~.phar"
CASTOR_TMPDIR="${TMPDIR:-/tmp}"

function output {
    style_start=""
    style_end=""
    if [ "${2:-}" != "" ]; then
    case $2 in
        "success")
            style_start="\033[0;32m"
            style_end="\033[0m"
            ;;
        "error")
            style_start="\033[31;31m"
            style_end="\033[0m"
            ;;
        "info"|"warning")
            style_start="\033[33m"
            style_end="\033[39m"
            ;;
        "heading")
            style_start="\033[1;33m"
            style_end="\033[22;39m"
            ;;
    esac
    fi

    builtin echo -e "${style_start}${1}${style_end}"
}

output "${CASTOR_NAME} installer" "heading"

binary_dest="${HOME}/.local/bin"
custom_dir="false"

# Getops does not support long option names
while [[ $# -gt 0 ]]; do
case $1 in
    --install-dir=*)
        binary_dest="${1#*=}"
        custom_dir="true"
        shift # past argument=value
        ;;
    --install-dir)
        binary_dest="${2:-}"
        custom_dir="true"
        shift # past argument
        shift # past value
        ;;
    *)
        output "Unknown option $1" "error"
        output "Usage: ${0} [--install-dir=dir]"
        exit 1
        ;;
esac
done

# Run environment checks.
output "\nEnvironment check" "heading"

# Check that cURL or wget is installed.
downloader=""
if command -v curl >/dev/null 2>&1; then
    downloader="curl"
    output "  [*] cURL is installed" "success"
elif command -v wget >/dev/null 2>&1; then
    downloader="wget"
    output "  [*] wget is installed" "success"
else
    output "  [ ] ERROR: cURL or wget is required for installation" "error"
    exit 1
fi

# Check that PHP is installed.
if command -v php >/dev/null 2>&1; then
    output "  [*] PHP is installed" "success"
else
    output "  [ ] ERROR: PHP is required for installation" "error"
    exit 1
fi

if [[ "1" == "$(php -r 'echo version_compare(PHP_VERSION, "8.1", ">=");')" ]]; then
    output "  [*] PHP version: $(php -r 'echo PHP_VERSION;')" "success"
else
    output "  [ ] ERROR: PHP version $(php -r 'echo PHP_VERSION;') is not 8.1 or greater" "error"
    exit 1
fi

# todo: add support for static binary?

kernel=$(uname -s 2>/dev/null || /usr/bin/uname -s)
case ${kernel} in
    "Linux"|"linux")
        kernel="linux"
        ;;
    "Darwin"|"darwin")
        kernel="darwin"
        ;;
    *)
        output "OS '${kernel}' not supported" "error"
        exit 1
        ;;
esac

machine=$(uname -m 2>/dev/null || /usr/bin/uname -m)
case ${machine} in
    aarch64*|armv8*|arm64)
        machine="arm64"
        if [ "linux" = "${kernel}" ]; then
            output "  [ ] Your architecture (${machine}) is not currently supported" "error"
            exit 1
        fi
        ;;
    x86_64)
        machine="amd64"
        ;;
    *)
        output "  [ ] Your architecture (${machine}) is not currently supported" "error"
        exit 1
        ;;
esac

output "  [*] Your architecture (${machine}) is supported" "success"

platform="${kernel}-${machine}"

# The necessary checks have passed. Start downloading the right version.
output "\nDownload" "heading"

latest_url=${CASTOR_DOWNLOAD_URL_PATTERN/~platform~/${platform}}
output "  Downloading ${latest_url}...";
case $downloader in
    "curl")
        curl --fail --location "${latest_url}" > "${CASTOR_TMPDIR}/${CASTOR_TMP_NAME}"
        ;;
    "wget")
        wget -q --show-progress "${latest_url}" -O "${CASTOR_TMPDIR}/${CASTOR_TMP_NAME}"
        ;;
esac

# shellcheck disable=SC2181
if [ $? != 0 ]; then
    output "  The download failed." "error"
    exit 1
fi

if [ ! -d "${binary_dest}" ]; then
    if ! mkdir -p "${binary_dest}"; then
        binary_dest="."
    fi
fi

if [ "${custom_dir}" == "true" ]; then
    output "  Installing the phar into ${binary_dest} ..."
else
    output "  Installing the phar into your home directory..."
fi

if mv "${CASTOR_TMPDIR}/${CASTOR_TMP_NAME}" "${binary_dest}/${CASTOR_EXECUTABLE}"; then
    output "  The phar was saved to: ${binary_dest}/${CASTOR_EXECUTABLE}"
else
    output "  Failed to move the phar to ${binary_dest}." "error"
    rm "${CASTOR_TMPDIR}/${CASTOR_EXECUTABLE}"
    exit 1
fi

output "  Fixing the phar permissions."
chmod u+x "${binary_dest}/${CASTOR_EXECUTABLE}"

output "\n🦫  $("${binary_dest}/${CASTOR_EXECUTABLE}" --version) was installed successfully!" "success"

if [ "${custom_dir}" == "false" ]; then
    output "\nUse it as a local file:" "info"
    output "  ${binary_dest}/${CASTOR_EXECUTABLE}"
    output "\nOr add the following line to your shell configuration file:" "info"
    output "  export PATH=\"\$HOME/.local/bin:\$PATH\""
    output "\nOr install it globally on your system:" "info"
    output " mv ${binary_dest}/${CASTOR_EXECUTABLE} /usr/local/bin/${CASTOR_EXECUTABLE}"
    output "\nIf moving the file does not work, you might have to prefix the command with sudo."
    output "\nThen start a new shell and run '${CASTOR_EXECUTABLE}'" "info"

    output "\nSetup the autocompletion (optional):" "info"
    output " Run 'castor completion --help' and follow instructions."
fi
