#!/usr/bin/env bash

## <script src="./readability.js"></script>
## <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.16.0/themes/prism-okaidia.min.css" rel="stylesheet" />
## <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.16.0/components/prism-core.min.js" data-manual></script>
## <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.16.0/components/prism-bash.min.js"></script>
## <style>body {color: #272822; background-color: #272822; font-size: 0.8em;} </style>
: WARNING: This Genkit CLI install script is still in active development. Do not use outside of testing and providing feedback.

: ==========================================
:   Introduction
: ==========================================

# This script allows you to install the latest version of the "genkit" command by running:
#
:   curl -sL cli.genkit.dev | bash
#
# If you do not want to use this script, you can manually download the latest "genkit" binary.
#
# Linux:
#
:   curl -Lo ./genkit_bin https://storage.googleapis.com/genkit-assets-cli/prod/linux-x64/latest
#
# macOS:
#
:   curl -Lo ./genkit_bin https://storage.googleapis.com/genkit-assets-cli/prod/darwin-arm64/latest
#
# Windows:
#
:   curl -Lo ./genkit_bin.exe https://storage.googleapis.com/genkit-assets-cli/prod/win32-x64/latest.exe
#
# Alternatively, you can download a specific version.
#
:   curl -Lo ./genkit_bin https://storage.googleapis.com/genkit-assets-cli/prod/darwin-arm64/v1.15.5/genkit
#
# For Windows append ".exe" to the URL.
#
:   curl -Lo ./genkit_bin.exe https://storage.googleapis.com/genkit-assets-cli/prod/win32-x64/v1.15.5/genkit.exe
#
# Supported architectures: darwin-x64, darwin-arm64, linux-x64, linux-arm64, win32-x64
#
# For full details about installation options for the Genkit CLI
# please see our documentation.
#   https://genkit.dev/docs/devtools
#
# Please report bugs / issues with this script on GitHub.
#   https://github.com/genkit-ai/genkit
#

: ==========================================
:   Advanced Usage
: ==========================================

# The behavior of this script can be modified at runtime by passing environmental
# variables to the `bash` process.
#
# For curl execution (environment variables):
#
: curl -sL cli.genkit.dev | arg1=true arg2=false bash
#
# These arguments are optional, but be aware that explicitly setting them will help
# ensure consistent behavior if / when defaults are changed.
#

: -----------------------------------------
:  Upgrading - default: false
: -----------------------------------------

# By default, this script will not replace an existing "genkit" install.
# If you'd like to upgrade an existing install, use the upgrade option.
#
# Curl execution:
: curl -sL cli.genkit.dev | upgrade=true bash
#
# This operation could (potentially) break an existing install, so use it with caution.
#

: -----------------------------------------
:  Uninstalling - default false
: -----------------------------------------

# You can remove the binary by passing the "uninstall" flag.
#
# Curl execution:
: curl -sL cli.genkit.dev | uninstall=true bash
#
# This will remove the binary file and any cached data.
#

: -----------------------------------------
:  Local install switch
: -----------------------------------------

# To force a user-local install into $HOME/.local/bin (useful on systems without sudo),
# you can pass the following:
#
: curl -sL cli.genkit.dev | local=true bash
#
# You can also explicitly set a target path:
#
: curl -sL cli.genkit.dev | GENKIT_BINARY="$HOME/.local/bin/genkit" bash
#


: -----------------------------------------
:  Analytics - default true
: -----------------------------------------

# This script reports anonymous success / failure analytics.
# You can disable this reporting by setting the "analytics" variable to false.
#
# Curl execution:
: curl -sL cli.genkit.dev | analytics=false bash
#
# By default we report all data anonymously and do not collect any information
# except platform type (Darwin, Win, etc) in the case of an unsupported platform
# error.
#

: ==========================================
:   Source Code
: ==========================================

# Options: prod, next
channel="${channel:-prod}"

# Environment variable defaults (these can be overridden when piping the script)
analytics="${analytics:-true}"    # Set to "false" to disable analytics
uninstall="${uninstall:-false}"   # Set to "true" to uninstall
upgrade="${upgrade:-false}"       # Set to "true" to upgrade existing install

# This script contains a large amount of comments so you can understand
# how it interacts with your system. If you're not interested in the
# technical details, you can just run the command above.

# We begin by generating a unique ID for tracking the anonymous session.
CID=$(head -80 /dev/urandom | LC_ALL=c tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
# Credit: https://gist.github.com/earthgecko/3089509

# We can use this CID in all calls to the Google Analytics endpoint via
# this reusable function.
TRACKING_ID="G-VE2GNRL789"

send_analytics_event()
{
    if [ ! "$analytics" = "false" ]; then
        curl -s https://www.google-analytics.com/collect \
            -d "tid=$TRACKING_ID" \
            -d "t=event" \
            -d "ec=cli.genkit.dev" \
            -d "ea=$1" \
            -d "v=1" \
            -d "cid=$CID" \
            -o /dev/null
    fi

    # For now, just return success
    return 0
}

# We send one event to count the number of times this script is ran. At the
# end we also report success / failure, but it's possible that the script
# will crash before we get to that point, so we manually count invocations here.
send_analytics_event start

# Debug/verbosity: where to send stderr for version probes
if [ -n "${DEBUG-}" ] && [ "$DEBUG" != "0" ]; then
    VERBOSE_STDERR="/dev/stderr"
else
    VERBOSE_STDERR="/dev/null"
fi

# Helper: check whether sudo exists *and* is usable (non-interactive).
has_usable_sudo() {
    if command -v sudo >/dev/null 2>&1; then
        sudo -n true >/dev/null 2>&1 || return 1
        return 0
    fi
    return 1
}

# Helper: get effective UID in shells where $EUID may not be set.
get_euid() {
    if [ -n "${EUID-}" ]; then
        printf '%s' "$EUID"
    else
        id -u
    fi
}

# Capture any user-provided desired install target, but keep detection separate.
DESIRED_BINARY="$GENKIT_BINARY"

# Explicit local-install switch.
if [ "${local:-}" = "true" ]; then
    DESIRED_BINARY="$HOME/.local/bin/genkit"
fi

# We try to detect any existing binaries on $PATH or two common locations.
EXISTING_BINARY="$(command -v genkit 2>/dev/null)"
LOCAL_BINARY="$HOME/.local/bin/genkit"
# For info about why we place the binary at this location, see
# https://unix.stackexchange.com/a/8658
GLOBAL_BINARY="/usr/local/bin/genkit"
if [[ -z "$EXISTING_BINARY" ]]; then
    if [ -e "$LOCAL_BINARY" ]; then
        EXISTING_BINARY="$LOCAL_BINARY"
    elif [ -e "$GLOBAL_BINARY" ]; then
        EXISTING_BINARY="$GLOBAL_BINARY"
    fi
fi

# If the user asked for us to uninstall genkit, then do so.
if [ "$uninstall" = "true" ]; then
    if [[ -z "$DESIRED_BINARY" ]]; then
        TARGET="$EXISTING_BINARY"
    else
        TARGET="$DESIRED_BINARY"
    fi

    if [ -z "$TARGET" ]; then
        echo "Cannot detect any Genkit CLI installations."
        echo "Please manually remove any \"genkit\" binaries not in \$PATH."
    else
        echo "-- Removing binary file: $TARGET"
        uninstall_sudo=""
        uninstall_dir="$(dirname -- "$TARGET")"
        euid="$(get_euid)"
        if [ "$euid" -ne 0 ] && [ ! -w "$uninstall_dir" ] && has_usable_sudo; then
            uninstall_sudo="sudo"
        fi
        $uninstall_sudo rm -f -- "$TARGET" 2>/dev/null || true
    fi
    echo "-- Removing genkit cache..."
    rm -rf ~/.cache/genkit

    echo "-- genkit has been uninstalled"
    echo "-- All Done!"

    send_analytics_event uninstall
    exit 0
fi

# We need to ensure that we don't mess up an existing "genkit"
# install, so before doing anything we check to see if this system
# has "genkit" installed and if so, we exit out.
echo "-- Checking for existing genkit installation..."

if [[ ! -z "$EXISTING_BINARY" ]]; then
    # Only treat as installed if the detected binary actually exists and is executable
    if [ -x "$EXISTING_BINARY" ]; then
        INSTALLED_GENKIT_VERSION=$("$EXISTING_BINARY" --version 2>"$VERBOSE_STDERR")
    else
        INSTALLED_GENKIT_VERSION=""
    fi

    # In the case of a corrupt genkit install, we wont be able to
    # retrieve a version number, so to keep the logs correct, we refer to
    # your existing install as either the CLI version or as a "corrupt install"
    if [[ ! -z "$INSTALLED_GENKIT_VERSION" ]]; then
        GENKIT_NICKNAME="genkit@$INSTALLED_GENKIT_VERSION"
    else
        GENKIT_NICKNAME="a corrupted genkit binary"
    fi

    # Skip npm check - assume binary install
    # If the user didn't pass upgrade=true, then we print the command to do an upgrade and exit
    if [ ! "$upgrade" = "true" ]; then
        echo "Your machine has $GENKIT_NICKNAME installed."
        echo "If you would like to upgrade your install run: curl -sL cli.genkit.dev | upgrade=true bash"

        send_analytics_event already_installed
        exit 0
    else
        # If the user did pass upgrade=true, then we allow the script to continue and overwrite the install.
        echo "-- Your machine has $GENKIT_NICKNAME, attempting upgrade..."

        send_analytics_event upgrade
    fi
fi

echo "-- Checking your machine type..."

# Now we need to detect the platform we're running on (Linux / Mac / Other)
# so we can fetch the correct binary and place it in the correct location
# on the machine.

# We use "tr" to translate the uppercase "uname" output into lowercase
UNAME=$(uname -s | tr '[:upper:]' '[:lower:]')

# Detect architecture
ARCH=$(uname -m)
case "$ARCH" in
    x86_64)     ARCH_SUFFIX="x64";;
    aarch64|arm64) ARCH_SUFFIX="arm64";;
    *)          ARCH_SUFFIX="x64";;  # Default to x64
esac

# Then we map the output to the names used on the GitHub releases page
case "$UNAME" in
    linux*)     MACHINE="linux-${ARCH_SUFFIX}";;
    darwin*)    MACHINE="darwin-${ARCH_SUFFIX}";;
    mingw*|msys*|cygwin*) MACHINE="win32-x64";;
esac

# If we never define the $MACHINE variable (because our platform is neither Mac,
# Linux, or Windows), then we can't finish our job, so just log out a helpful message
# and close.
if [[ -z "$MACHINE" ]]; then
    echo "Your operating system is not supported, if you think it should be please file a bug."
    echo "https://github.com/genkit-ai/genkit/"
    echo "-- All done!"

    send_analytics_event "missing_platform_${UNAME}_${ARCH}"
    exit 0
fi

# We have enough information to generate the binary's download URL.
DOWNLOAD_URL="https://storage.googleapis.com/genkit-assets-cli/$channel/$MACHINE/latest"
echo "-- Downloading binary from $DOWNLOAD_URL"

# We use "curl" to download the binary with a flag set to follow redirects
# (GitHub download URLs redirect to CDNs) and a flag to show a progress bar.
if ! curl -o "/tmp/genkit_standalone.tmp" --fail -L --progress-bar "$DOWNLOAD_URL"; then
    echo "Something went wrong. Failed to download binary from $DOWNLOAD_URL"
    echo "Please file a bug with your system information on GitHub."
    echo "https://github.com/genkit-ai/genkit/"

    send_analytics_event download_failure

    exit 1
fi

# Determine install target: prefer user-provided location, otherwise global default.
GENKIT_BINARY=${DESIRED_BINARY:-$GLOBAL_BINARY}
INSTALL_DIR=$(dirname -- "$GENKIT_BINARY")

# We need to ensure that the INSTALL_DIR exists.
# On some platforms like the Windows Subsystem for Linux it may not.
# We created it using a non-destructive mkdir command.
mkdir -p -- "$INSTALL_DIR" 2> /dev/null

# If the directory does not exist or is not writable, we resort to sudo when available and usable.
sudo_cmd=""
if [ ! -w "$INSTALL_DIR" ]; then
    euid="$(get_euid)"
    if [ "$euid" -eq 0 ]; then
        sudo_cmd=""  # already root
    elif has_usable_sudo; then
        sudo_cmd="sudo"
    else
        echo "-- '$INSTALL_DIR' is not writable and 'sudo' is not available; falling back to a user-local install."
        GENKIT_BINARY="$LOCAL_BINARY"
        INSTALL_DIR=$(dirname -- "$GENKIT_BINARY")
        mkdir -p -- "$INSTALL_DIR" 2> /dev/null
        sudo_cmd=""
    fi
fi

$sudo_cmd mkdir -p -- "$INSTALL_DIR"
$sudo_cmd mv -f "/tmp/genkit_standalone.tmp" "$GENKIT_BINARY"

# Once the download is complete, we mark the binary file as readable
# and executable (+rx).
echo "-- Setting permissions on binary... $GENKIT_BINARY"
$sudo_cmd chmod +rx "$GENKIT_BINARY"

# If all went well, the "genkit" binary should be located on our PATH so
# we'll run it once, asking it to print out the version. This is helpful as
# standalone genkit binaries do a small amount of setup on the initial run
# so this not only allows us to make sure we got the right version, but it
# also does the setup so the first time the developer runs the binary, it'll
# be faster.
VERSION=$("$GENKIT_BINARY" --version 2>"$VERBOSE_STDERR")

# If no version is detected then clearly the binary failed to install for
# some reason, so we'll log out an error message and report the failure
# to headquarters via an analytics event.
if [[ -z "$VERSION" ]]; then
    echo "Something went wrong, genkit has not been installed."
    echo "Please file a bug with your system information on GitHub."
    echo "https://github.com/genkit-ai/genkit/"
    echo "-- All done!"

    send_analytics_event binary_check_failure
    exit 1
fi

# In order for the user to be able to actually run the "genkit" command
# without specifying the absolute location, the INSTALL_DIR path must
# be present inside of the PATH environment variable.

echo "-- Checking your PATH variable..."
case ":$PATH:" in
  *":$INSTALL_DIR:"*) : ;;
  *)
    echo ""
    echo "It looks like $INSTALL_DIR isn't on your PATH."
    if [ "$INSTALL_DIR" = "$HOME/.local/bin" ]; then
        echo "Heads up: many distros expect user-local binaries in \$HOME/.local/bin."
    fi
    echo "Please add the following line to either your ~/.profile or ~/.bash_profile, then restart your terminal."
    echo ""
    echo "export PATH=\"$INSTALL_DIR:\$PATH\""
    echo ""
    echo "For more information about modifying PATHs, see https://unix.stackexchange.com/a/26059"
    echo ""
    send_analytics_event missing_path
  ;;
esac

# We also try to upgrade the local binary if it exists.
# This helps prevent having two mismatching versions of "genkit".
if [[ "$GENKIT_BINARY" != "$LOCAL_BINARY" ]] && [ -e "$LOCAL_BINARY" ]; then
  echo "-- Upgrading the local binary installation $LOCAL_BINARY..."
  cp "$GENKIT_BINARY" "$LOCAL_BINARY" 2>/dev/null || true # best effort, okay if it fails.
  chmod +x "$LOCAL_BINARY" 2>/dev/null || true
fi

# Since we've gotten this far we know everything succeeded. We'll just
# let the developer know everything is ready and take our leave.
echo "-- genkit@$VERSION is now installed"
echo "-- All Done!"

send_analytics_event success
exit 0

# ------------------------------------------
#   Notes
# ------------------------------------------
#
# This script contains hidden JavaScript which is used to improve
# readability in the browser (via syntax highlighting, etc), right-click
# and "View source" of this page to see the entire bash script!
#
# You'll also notice that we use the ":" character in the Introduction
# which allows our copy/paste commands to be syntax highlighted, but not
# ran. In bash : is equal to `true` and true can take infinite arguments
# while still returning true. This turns these commands into no-ops so
# when ran as a script, they're totally ignored.
#
