#!/usr/bin/env bash
set -o pipefail
IFS=$'\n\t'

# Copyright (c) Cloud Linux GmbH & Cloud Linux Software, Inc 2010-2020 All Rights Reserved
#
# Licensed under CLOUD LINUX LICENSE AGREEMENT
# http://cloudlinux.com/docs/LICENSE.TXT
# This script helps install ELS repository

# Before use the script you should get a license key in CLN. Then use to to run
# the script and wait until it done.


VERSION="0.6"
REPO_PATH="/etc/apt/sources.list.d/ubuntu-els.list"
CLN_SERVER="https://cln.cloudlinux.com"
CLN_UNREGISTER_SERVER="https://cln.cloudlinux.com/cln/api/els/server/unregister"
TOKEN_END_POINT="/cln/api/els/server/register"
AUTH_CONF_PATH="/etc/apt/auth.conf.d/ubuntu20_04-els.conf"
PACKAGE_URI="https://repo.tuxcare.com/ubuntu20_04-els/els-os-release_install_amd64.deb"

exec 3>&1
trap "exec 3>&-" EXIT

log() {
    printf "%s\\n" "$1" 1>&3
}

show_help() {
    cat << EOF
    Install script for ELS by TuxCare repository

    Options:
        -h, --help      Show this help message
        -V, --version   Show version information
        --license-key   User license key
        --cln-server    CLN server
        --hostname      Custom hostname
        --force         Force re-register if repo exist
        --delete        Delete ELS from server
EOF
}

do_opts() {
    if [ $# -eq 0 ]; then
        log "$(show_help)"
        exit 1
    fi
    while [ $# -gt 0 ]; do
        key="$1"
        case $key in
            -h|--help)
            log "$(show_help)"
            exit 0
            ;;
            -V|--version)
            show_version
            exit 0
            ;;
            --license-key)
            LICENSE_KEY="$2"
            shift
            ;;
            --cln-server)
            CLN_SERVER="$2"
            shift
            ;;
            --hostname)
            HOSTNAME="$2"
            shift
            ;;
            --force)
            FORCE=true
            ;;
            --delete)
            DELETE=true
            ;;
            *)
            log "Unknown option: $key"
            log "$(show_help)"
            exit 1
            ;;
        esac
        shift
    done
    if [ -z "$LICENSE_KEY" ] && [ "$DELETE" != "true" ]; then
        log "Required argument not provided: --license-key"
        log "$(show_help)"
        exit 1
    fi
}

show_version() {
    log "$VERSION"
}

pre_run_check() {
    log "Checking if els-os-release is already installed... "
    if apt list --installed 2>/dev/null | grep -q "^els-os-release/"; then
        log "els-os-release package is already installed."
        return 1
    fi
    log "Ok"
    return 0
}

get_auth_token() {
    log "Request repository token for this server... "
    local data="{\"key\": \"$3\", \"host_name\": \"$2\"}"
    local ret
    ret=$(curl -s -X POST -H "Content-Type: application/json" -H "Accept: application/json" -d "$data" "$1")
    if [ $? -ne 0 ]; then
        log "Error (Curl command failed)"
        return 1
    fi
    local token
    token=$(echo "$ret" | grep -oP '"token":"\K[^"]*')
    if [ -n "$token" ]; then
        log "Ok"
        echo "$token"
        return 0
    fi
    log "Error (No token was returned from CLN)"
    return 1
}

get_distro_info() {
    local system_release_path="/etc/lsb-release"
    local key="$1"
    log "Get OS info... "
    if [ ! -f "$system_release_path" ]; then
        log "Error (Could not determine OS: $system_release_path does not exist)"
        return 0
    fi
    value=$(grep -oP "^$key=\K.*" "$system_release_path")
    if [ -z "$value" ]; then
        log "Error (Could not determine OS: $key not found in $system_release_path)"
        return 0
    fi

    echo "$value"
    return 0
}

get_distro_name() {
    get_distro_info "DISTRIB_ID"
}

get_distro_version() {
    get_distro_info "DISTRIB_RELEASE"
}

remove_els() {
    # This will remove repo configuration
    log "Purging els-os-release package... "
    if apt-get purge -yq els-os-release 1>&3; then
        log "Ok"
    else
        log "Error (Could not purge els-os-release package)"
        return 1
    fi

    log "Removing authentication configuration file... "
    if rm -f "$AUTH_CONF_PATH" 1>&3; then
        log "Ok"
    else
        log "Error (Could not remove auth configuration file: $AUTH_CONF_PATH)"
        return 1
    fi

    log "Ubuntu 20.04 ELS deleted successfully"
    return 0
}

extract_token() {
    token=$(sed -n 's/^login \([^[:space:]]*\).*/\1/p' "$AUTH_CONF_PATH")

    if [[ -z "$token" || "$token" != *SERVER* ]]; then
        log "Couldn't extract token from $AUTH_CONF_PATH"
        return 1
    fi

    echo "$token"
    return 0
}

unregister_token() {
    if ! token=$(extract_token); then
        return 1
    fi

    response=$(curl -i -s -X POST "${CLN_UNREGISTER_SERVER}?token=${token}")
    curl_exit_code=$?

    if [ $curl_exit_code -ne 0 ]; then
        log "ERROR: Failed to connect to unregister server (curl exited with status: $curl_exit_code)"
        return 1
    fi

    if ! echo "$response" | grep -qi '^HTTP/[0-9.]*[[:space:]]200'; then
        if [[ -z "$response" ]]; then
            log "DELETE: elstoken wasn't found. Server is not registered"
        else
            log "Got incorrect status from CLN: $response"
        fi
        return 1
    fi

    log "Unregistered successfully"
    return 0
}

delete_els() {
    if ! pre_run_check; then
        if [ "$FORCE" = "true" ]; then
            # Force mode: try to unregister but continue even if it fails
            unregister_token || log "Warning: Failed to unregister, but continuing with force delete"
            remove_els
        else
            if ! unregister_token; then
                log "Couldn't deactivate account"
                return 12
            fi
            remove_els
        fi
    else
        log "ELS is not installed"
    fi
    return 0
}

install_els_os_release() {
    log "Installing els-os-release..."

    TEMP_DEB=$(mktemp /tmp/els-os-release-XXXXXX.deb)

    if ! curl -fsSL -o "$TEMP_DEB" "$PACKAGE_URI"; then
        log "Error: Couldn't download els-os-release.deb"
        return 1
    fi

    if ! chmod 644 "$TEMP_DEB"; then
        log "Error: Couldn't set permissions for $TEMP_DEB"
        return 2
    fi

    if ! apt-get -yq install "$TEMP_DEB"; then
        log "Error: Couldn't install els-os-release"
        return 3
    fi

    if ! rm -f "$TEMP_DEB"; then
        log "Error: Failed to remove temporary package file"
        return 4
    fi
}

check_superuser_privileges() {
    log "Checking for superuser privileges..."
    if [ "$(id -u)" -ne 0 ]; then
        log "Error: This script must be run with superuser privileges"
        return 1
    fi
    log "Superuser privileges confirmed"
    return 0
}

main() {
    do_opts "$@"

    if ! check_superuser_privileges; then
        return 14
    fi

    if [ "$(get_distro_name)" != "Ubuntu" ]; then
        return 11
    fi

    if [ "$(get_distro_version)" != "20.04" ]; then
        return 12
    fi

    if [ "$DELETE" = "true" ]; then
        delete_els
        return $?
    fi

    if ! pre_run_check; then
        if [ "$FORCE" = "true" ]; then
            unregister_token || log "Warning: Failed to unregister, but continuing with force reinstall"
            remove_els
        else
            log "For re-registration license run script with --force ."
            return 2
        fi
    fi

    if [ -z "$HOSTNAME" ]; then
        HOSTNAME="$(hostname)"
    fi

    log "Registering in CLN..."
    local url="${CLN_SERVER}${TOKEN_END_POINT}"
    local token
    token=$(get_auth_token "$url" "$HOSTNAME" "$LICENSE_KEY")
    if [ $? -ne 0 ]; then
        return 3
    fi

    log "Applying repository token for this server..."
    if ! install_els_os_release; then
        return 9
    fi

    if ! echo -e "machine repo.tuxcare.com/ubuntu20_04-els/\nlogin $token\npassword" > "$AUTH_CONF_PATH"; then
        log "Error (Could not write to $AUTH_CONF_PATH)"
        return 10
    fi

    log "Updating cache..."
    if ! apt-get -yq update 1>&3; then
        log "Error (Could not update repository cache)"
        return 6
    fi

    log "Ubuntu 20.04 ELS installed successfully"

    return 0
}

main "$@"
