#!/bin/bash

# install.sh
#
# This is just a little script that can be downloaded from the internet to
# install Autumn Labs client. It just does platform detection, downloads the
# client package if needed, and installs the required binaries.
#
# Heavily inspired by the Vector install script at 
# https://github.com/vectordotdev/vector/blob/master/distribution/install.sh

set -u

# If PACKAGE_VERSION is unset or empty, default it
PACKAGE_VERSION="${PACKAGE_VERSION:-"latest"}"

# Install directory
ROOT_DIR="$HOME/.autumnlabs"

# API constants
API_URL="https://client.autumnlabs.io"

_divider="--------------------------------------------------------------------------------"
_prompt=">>>"
_indent="   "
_input="# "

header() {
    printf "

             █████████    ████                
           █████████████   █████              
          █████     █████   █████             
          ████        █████   ████        ████
                       █████   █████     █████
                        █████   █████████████ 
                          ████    █████████   

                  A U T U M N  L A B S
                    Client Installer

$_divider
Website: https://autumnlabs.io
Docs: https://docs.autumnlabs.io
$_divider
"
}

usage() {
    cat 1>&2 <<EOF
The installer for Autumn Labs client (https://autumnlabs.io)

USAGE:
    install [FLAGS] [OPTIONS]

FLAGS:
    -h, --help              Prints help information
    -y, --yes               Disable confirmation prompt. 
                                Default: False (show confirmation prompt).
    -u, --url [URL]         Use the specified client API URL base 
                                Default: ${API_URL}
    -v, --verbose           Enable verbose output. 
                                Default: False (no verbose output).
    -s, --secret [SECRET]   Use the specified secret. 
                                Default: None (prompt for secret).
    -i, --insecure         Allow insecure downloads (skip SSL verification).
                                Default: False (verify SSL).
EOF
}

main() {
    header

    local prompt=yes
    local api_url="${API_URL}"
    local verbose=False
    local secret=""
    local first_install=True
    local insecure=False
    
    while [[ $# -gt 0 ]]; do
        case "$1" in
            -h|--help)
                usage
                exit 0
                ;;
            -y|--yes)
                prompt=no
                printverbose "$_prompt Prompt: $prompt"
                ;;
            -u|--url)
                if [[ -z "$2" || "$2" == -* ]]; then
                    err "Error: --url requires a value"
                fi
                api_url="$2"
                printverbose "$_prompt API URL: $api_url"
                shift
                ;;
            -v|--verbose)
                verbose=True
                printverbose "$_prompt Verbose mode enabled"
                ;;
            -s|--secret)
                if [[ -z "$2" || "$2" == -* ]]; then
                    err "Error: --secret requires a value"
                fi
                secret="$2"
                printverbose "$_prompt Secret: $secret"
                shift
                ;;
            *)
                err "Unknown flag: $1"
                ;;
        esac
        shift
    done

    # Confirm with the user before proceeding to install Autumn Labs client from a pre-built archive.
    if is_client_installed; then
        first_install=False
        if [ "$prompt" = "yes" ]; then
            echo "$_prompt Autumn Labs client is already installed."
            echo "$_prompt Stop current services and update to [${PACKAGE_VERSION}]? (y/n)"
            while true; do
                read -rp "$_input" _choice </dev/tty
                case $_choice in
                    n | no | N | NO)
                        err "exiting"
                        ;;
                    y | yes | Y | YES)
                        break
                        ;;
                    *)
                        echo "Please enter y or n."
                        ;;
                esac
            done
            echo ""
            echo "$_divider"
            echo ""
        fi
        echo "$_prompt Stopping services..."
        "${ROOT_DIR}/bin/al" stop --force
        echo "done"
    fi

    get_architecture
    local _arch="$RETVAL"

    local _dir
    _dir="$(mktemp -d 2>/dev/null || mktemp -d -t autumnlabs-install)"
    mkdir -p "$_dir"
    local _file="${_dir}/al.tar.gz"

    # check if client package exists in current working directory
    local _cwd=$(dirname "$(realpath "$0")")
    if [ -f "$_cwd/al.tar.gz" ]; then
        printverbose "$_prompt Found client package in script directory. Skipping download."
        cp "$_cwd/al.tar.gz" "$_file"
    else
        printverbose "$_prompt We'll be installing Autumn Labs client via a pre-built archive at ${api_url}/get/latest/${_arch}"
        if [ "$prompt" = "yes" ]; then
            echo "$_prompt Ready to proceed? (y/n)"
            while true; do
                read -rp "$_input" _choice </dev/tty
                case $_choice in
                    n | no | N | NO)
                        err "exiting"
                        ;;
                    y | yes | Y | YES)
                        break
                        ;;
                    *)
                        echo "Please enter y or n."
                        ;;
                esac
            done
        fi
        
        printverbose "$_prompt Downloading from ${api_url}/get/${PACKAGE_VERSION}/${_arch}/al.tar.gz"
        local _url="${api_url}/get/${PACKAGE_VERSION}/${_arch}/al.tar.gz"
        downloader "$_url" "$_file" "$_arch"
    fi
    echo "$_divider"
    echo ""

    # Create temporary directory to verify the downloaded package
    local _verify_dir
    _verify_dir="$(mktemp -d 2>/dev/null || mktemp -d -t autumnlabs-verify)"
    mkdir -p "$_verify_dir"
    
    # Extract the package to verify directory
    printverbose "$_prompt Verifying downloaded package..."
    tar -zxf "$_file" -C "$_verify_dir"
    
    # Check version and architecture
    local _downloaded_version=$("$_verify_dir/al" version | grep "CLI version:" | sed 's/CLI version: *//')
    if [ "${_downloaded_version:0:1}" != "v" ]; then
        _downloaded_version="v$_downloaded_version"
    fi
    local _downloaded_arch=$("$_verify_dir/al" version | grep "Architecture:" | sed 's/Architecture: *//')
    
    # Clean up verify directory
    rm -rf "$_verify_dir"
    
    # Verify version matches requested version if not "latest"
    if [ "$PACKAGE_VERSION" != "latest" ]; then
        if [ "$_downloaded_version" != "$PACKAGE_VERSION" ]; then
            err "Error: Downloaded version: $_downloaded_version does not match requested version: $PACKAGE_VERSION"
        fi
    fi
    
    # Verify architecture matches
    if [ "$_downloaded_arch" != "$_arch" ]; then
        err "Error: Downloaded architecture: $_downloaded_arch does not match requested architecture: $_arch"
    fi

    echo "$_prompt Installing client for architecture: $_arch"
    printverbose "$_prompt Unpacking"
    mkdir -p "$ROOT_DIR/bin"
    tar -zxf "$_file" -C "$ROOT_DIR/bin"

    ignore rm -rf "$_dir"

    # Add the client to the PATH if the user wants to
    local _add_to_path=True
    if [ "$prompt" = "yes" ]; then
        echo "$_prompt Do you want to add the client to your PATH? (y/n)"
        while true; do
            read -rp "$_input" _choice </dev/tty
            case $_choice in
                n | no | N | NO)
                    _add_to_path=False
                    break
                    ;;
                y | yes | Y | YES)
                    _add_to_path=True
                    break
                    ;;
                *)
                    ehco "Please enter y or n."
                    ;;
            esac
        done
    fi

    if [ "$_add_to_path" = "True" ]; then
        add_to_path
    fi

    # Print version and info for installed client
    echo "$_prompt Installed client version: $_downloaded_version"
    echo "$_prompt Architecture: $_downloaded_arch"
    echo "$_prompt Path: $ROOT_DIR/bin/al"

    echo "$_prompt Install succeeded! 🚀"
    echo "$_divider"
    echo ""
    
    if [ "$first_install" = "True" ]; then
        echo "$_prompt Let's set up your first station!"
        local _register_cmd="${ROOT_DIR}/bin/al register"
        if [ -n "$api_url" ]; then
            echo "$_prompt API URL: $api_url"
            _register_cmd="${_register_cmd} --url $api_url"
        fi
        if [ -n "$secret" ]; then
            echo "$_prompt Secret: $secret"
            _register_cmd="${_register_cmd} --secret $secret"
        fi
        echo ""
        ${_register_cmd}
        if [ $? -ne 0 ]; then
            echo "$_divider"
            echo "Failed to register client"
            print_support
        fi
    else
        echo "$_prompt Restarting services..."
        printverbose "$_prompt Stopping services..."
        "${ROOT_DIR}/bin/al" stop --force
        printverbose "$_prompt Starting services..."
        "${ROOT_DIR}/bin/al" start
    fi
}

is_client_installed() {
    if [ -f "$ROOT_DIR/bin/al" ]; then
        return 0
    else
        return 1
    fi
}

add_to_path() {
    local profile_files=("$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.profile")
    for profile in "${profile_files[@]}"; do
        if [[ -f "$profile" ]]; then
            if ! grep -q 'export PATH="$HOME/.autumnlabs/bin:$PATH"' "$profile"; then
                echo 'export PATH="$HOME/.autumnlabs/bin:$PATH"' >>"$profile"
                echo "Added ~/.autumnlabs/bin to PATH in $profile"
            else
                echo "~/.autumnlabs/bin already in PATH in $profile"
            fi
        fi
    done
    echo "Please restart your shell session for the changes to take effect."
}

get_architecture() {
    local _ostype _cputype _arch
    _ostype="$(uname -s)"
    _cputype="$(uname -m)"

    if [ "$_ostype" = Linux ]; then
        if [ "$(uname -o)" = Android ]; then
            _ostype=Android
        fi
    fi

    if [ "$_ostype" = Darwin ] && [ "$_cputype" = i386 ]; then
        # Darwin `uname -m` lies
        if sysctl hw.optional.x86_64 | grep -q ': 1'; then
            _cputype=amd64
        fi
    fi

    case "$_ostype" in
        Linux)
            _ostype=linux
            ;;

        Darwin)
            _ostype=darwin
            ;;
        MINGW* | MSYS* | CYGWIN* | Windows_NT)
            echo "$_prompt Detected Windows OS. Please use the Windows installer (install.bat) instead."
            exit 1
            ;;
        *)
            err "Unsupported OS type: $_ostype"
            ;;
    esac

    case "$_cputype" in
        aarch64 | arm64)
            _cputype=arm64
            ;;

        x86_64 | x86-64 | x64 | amd64)
            _cputype=amd64
            ;;
        *)
            err "Unsupported CPU type: $_cputype"
            ;;

    esac

    _arch="${_ostype}/${_cputype}"
    printverbose "$_prompt Architecture: $_arch"

    RETVAL="$_arch"
}

err() {
    echo "$1" >&2
    exit 1
}

printverbose() {
    if [ "$verbose" = "True" ]; then
        echo "$1"
    fi
}

check_cmd() {
    command -v "$1" > /dev/null 2>&1
}

need_cmd() {
    if ! check_cmd "$1"; then
        err "need '$1' (command not found)"
    fi
}

# Ignore the output of a command
ignore() {
    "$@" > /dev/null 2>&1
}

# This wraps curl to download files
downloader() {
    local _err
    _err=$(curl --silent --show-error --fail "$1" --output "$2" 2>&1)
    if [ -n "$_err" ]; then
        # echo "$_err" >&2
        if echo "$_err" | grep -q 404$; then
            err "installer for platform '$3' not found, this may be unsupported"
        else
            echo "error downloading from $1"
        fi
        print_support
    fi
}

print_support() {
    echo "$_prompt Please contact support@autumnlabs.io for help"
    echo ""
    exit 1
}

main "$@"