#!/usr/bin/env bash
#
# Install the asdf package manager from github repository
#
# Optional argument is the version name of asdf which can be found at: https://github.com/asdf-vm/asdf/releases/tag/v<versionNumber>
# Script needs root or sudoer right which allows to white asdf binary into /usr/local/bin
# Asf installed on /caldrons/asdf
set -eu 
set -o pipefail 

# ================================================== #
readonly scriptSimplePath="${BASH_SOURCE[0]}"
readonly scriptNameFQP="$(cd "$(dirname "$scriptSimplePath")" && pwd)/$(basename "$scriptSimplePath")"
readonly line="$(printf '%100s' | tr ' ' '=')"

readonly caldronName='asdf'
readonly githubRepo='https://github.com/asdf-vm/asdf'
readonly installRoot='/caldrons'
readonly binaryDest='/usr/local/bin/asdf'

readonly os='linux'
readonly arch='amd64'
readonly assetExt='tar.gz'

export asdfDataDir="/caldrons/asdf/data"

# ================================================== #
#                    Utility Functions               #
# ================================================== #

log() {
    printf '[%s] %s\n' "$1" "$2"
}

info()  { log INFO  "$*"; }
warn()  { log WARN  "$*"; }
error() { log ERROR "$*"; }

die() {
    error "$1"
    exit 1
}

usage() {
    cat << EOF
Usage: $scriptNameFQP <version>

Install asdf to /caldrons/asdf with version X.Y.Z

Example:
  sudo -E ./$scriptNameFQP 0.18.0

Latest releases: $githubRepo/releases
EOF
}

# ================================================== #
#                 Argument Parsing                   #
# ================================================== #

parseAndValidateArgs() {
    if [ "${#}" -ne 1 ]; then
        printf '%s\n' "$line"
        printf "The asdf version number is required for this script\n"
        usage
        exit 10
    fi

    local rawVersion="$1"
    local normalized="${rawVersion#v}"

    if ! [[ "$normalized" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
        printf '%s\n' "$line"
        die "Invalid version format: '$rawVersion'. Expected X.Y.Z"
    fi

    readonly version="$normalized"
    declare -g version
}

# ================================================== #
#                   Pre-Checks                       #
# ================================================== #

ensureRunningAsRoot() {
    if [[ ${EUID} -ne 0 ]]; then
        die "Must be run as root or via 'sudo -E'"
    fi
}

checkRequiredTools() {
    for cmd in curl grep sha256sum; do
        if ! command -v "$cmd" >/dev/null 2>&1; then
            die "Required tool '$cmd' not found"
        fi
    done
}

verifyReleaseExists() {
    local url
    url=$(buildDownloadUrl)
    if ! curl --output /dev/null --silent --head --fail "$url"; then
        die "Version v$version not found at $url"
    fi
}

isAsdfUpToDate() {
  if [[ -f "$binaryDest" ]]; then
    info "Check asdf Installed version"
    local installedVersion="$("$binaryDest" --version 2>/dev/null | grep -Eo '([0-9]+\.[0-9]+\.[0-9]+)' || true)"
    warn "Asdf existing installed version: v$installedVersion" 
    if [[ "$installedVersion" = $version ]]; then
      info "asdf v$version is already installed. Skipping re-installation."
      return 1
    fi
  fi
}

# ================================================== #
#                  Installation Steps                #
# ================================================== #

buildDownloadUrl() {
    echo "$githubRepo/releases/download/v$version/asdf-v$version-$os-$arch.$assetExt"
}

prepareDirectories() {
    local caldronDir="$installRoot/$caldronName"
    info "Creating directory: $caldronDir"
    mkdir -p "$caldronDir"
}

downloadArchive() {
    local url
    url=$(buildDownloadUrl)
    local filename="asdf-v$version-$os-$arch.$assetExt"
    local targetDir="$installRoot"

    cd "$targetDir"

    if [[ -f "$filename" ]]; then
        info "Archive already exists: $filename (skipping download)"
        return
    fi

    info "Downloading from: $url"
    if ! curl -fLo "$filename" "$url"; then
        die "Download failed"
    fi
}

verifyChecksum() {
    local filename="asdf-v$version-$os-$arch.$assetExt"
    local archivePath="$installRoot/$filename"
    local shasumsUrl="$githubRepo/releases/download/v$version/SHASUMS.txt"
    local shasumsFile="/tmp/SHASUMS.txt.$$"

    trap 'rm -f "$shasumsFile"' EXIT

    info "Downloading checksums from: $shasumsUrl"
    if ! curl -fLo "$shasumsFile" "$shasumsUrl"; then
        die "Failed to download SHASUMS.txt"
    fi

    info "Verifying SHA256 checksum..."
    if ! grep "$filename" "$shasumsFile" | sha256sum -c - >/dev/null 2>&1; then
        die "Checksum verification failed for $filename"
    fi

    info "Checksum verified successfully."
}

installBinary() {
    local archive="asdf-v$version-$os-$arch.$assetExt"
    local workDir="$installRoot/$caldronName"

    info "Extracting and installing binary..."

    # DO NOT use --strip-components=1 — tarball contains just 'asdf'
    tar -xzf "$installRoot/$archive" -C "$workDir"

    cp "$workDir/asdf" "$binaryDest"
    chmod +x "$binaryDest"

    info "Installed binary: $binaryDest"
}

setupDataDirectory() {
    local username
    username="$(logname || echo "$SUDO_USER")"

    info "Setting up data directory: $asdfDataDir"
    mkdir -p "$asdfDataDir"
    chown -R "$username" "$installRoot/$caldronName"
}

configureUserProfile() {
    local username homeDir profileFile
    username="$(logname || echo "$SUDO_USER")"
    homeDir="$(getent passwd "$username" | cut -d: -f6 || echo "/home/$username")"
    profileFile="$homeDir/.profile"

    info "Updating $profileFile for user $username"

    sed -i '/#@ASDF Begin:/,/#@ASDF End:/d' "$profileFile" 2>/dev/null || true

    cat >> "$profileFile" << EOF
#@ASDF Begin: Configure Asdf datadir and shims paths
export ASDF_DATA_DIR=$asdfDataDir
export PATH="\$ASDF_DATA_DIR/shims:\$PATH"
#@ASDF End: Configuration
EOF

    chown "$username:$username" "$profileFile"
}

cleanupArtifacts() {
    local archive="$installRoot/asdf-v$version-$os-$arch.$assetExt"
    if [[ -f "$archive" ]]; then
        rm -f "$archive"
        info "Cleaned up archive: $archive"
    fi
}

# ================================================== #
#                      Main Pipeline                 #
# ================================================== #

declare -a INSTALL_STEPS=(
    parseAndValidateArgs
    ensureRunningAsRoot
    checkRequiredTools
    isAsdfUpToDate
    verifyReleaseExists
    prepareDirectories
    downloadArchive
    # verifyChecksum    # not yet available for asdf
    installBinary
    setupDataDirectory
    configureUserProfile
    cleanupArtifacts
)

runInstallationPipeline() {
    printf '%s\n' "$line"
    info "Starting installation of $caldronName v$1"
    printf '%s\n' "$line"

    for step in "${INSTALL_STEPS[@]}"; do
        info "Running step: $step"
        "$step" "$@"
    done

    printf '%s\n' "$line"
    info " $caldronName v$version installed successfully!"
    info "Run 'source ~/.profile' or re-login to use it."
    printf '%s\n' "$line"
}

# ================================================== #
#                     Entry Point                    #
# ================================================== #

if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    runInstallationPipeline "$@"
fi
