#!/bin/bash

CLN_REGISTER_SERVER="https://cln.cloudlinux.com/cln/api/els/server/register"
CLN_UNREGISTER_SERVER="https://cln.cloudlinux.com/cln/api/els/server/unregister"
LICENSE=""
HOSTNAME=`hostname`
AUTH_CONF_PATH="/etc/apt/auth.conf.d/php-els.conf"
PHP_REPO_PATH="/etc/apt/sources.list.d/php-els.list"
# Base URIs; the architecture-specific suffix (.amd64.deb / .arm64.deb) is
# appended at runtime by detect_arch() based on the host architecture.
ALT_COMMON_BASE_URI="https://repo.alt.tuxcare.com/alt-common/alt-common-release-install"
PHP_RELEASE_BASE_URI="https://repo.alt.tuxcare.com/alt-php-els/els-php-release-install"
ALT_COMMON_PACKAGE_URI=""
PACKAGE_URI=""


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

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

show_usage() {
    echo 'Usage: install-els-alt-php-deb-repo.sh [OPTION]...'
    echo ''
    echo '  -l, --license-key   User license key'
    echo '  -i, --imunify       Use Imunify360 license for repository access.'
    echo '                      Only available when Imunify360 is installed on this system'
    echo '                      and has a valid license. Do not use otherwise.'
    echo '  -f, --force         Force re-register if ELS is already installed'
    echo '  -d, --delete        Delete ELS from server'
    echo '  -h, --help          Show this message and exit'
}

do_opts() {
    if [ $# -eq 0 ]; then
        log "$(show_usage)"
        exit 1
    fi
    while [ $# -gt 0 ]; do
        key="$1"
        case $key in
            -h|--help)
                log "$(show_usage)"
                exit 0
                ;;
            -l|--license-key)
                if [[ -z "$2" || "$2" == -* ]]; then
                    log "Error: --license-key requires an argument"
                    log "$(show_usage)"
                    exit 1
                fi
                LICENSE="$2"
                shift
                ;;
            -i|--imunify)
                IMUNIFY=true
                ;;
            -f|--force)
                FORCE=true
                ;;
            -d|--delete)
                DELETE=true
                ;;
            -*|--*)
                log "Unknown option: $key"
                log "$(show_usage)"
                exit 1
                ;;
        esac
        shift
    done

    # For install: require either --license-key or --imunify (protection from accidental run without credentials)
    if [ "$DELETE" != "true" ] && [ -z "$LICENSE" ] && [ "$IMUNIFY" != "true" ]; then
        log "Must specify either --license-key or --imunify for installation."
        log "Use --imunify only on systems where Imunify360 is installed with a valid license."
        log "$(show_usage)"
        exit 1
    fi
    # Cannot use both at once
    if [ -n "$LICENSE" ] && [ "$IMUNIFY" = "true" ]; then
        log "Cannot use --license-key and --imunify together. Choose one."
        log "$(show_usage)"
        exit 1
    fi
}

# Get Imunify360 license id from imunify360-agent (for --imunify mode).
# Outputs the id to stdout and returns 0 on success, empty and return 1 otherwise.
get_imunify_license_id() {
    local tmp id
    if ! command -v imunify360-agent >/dev/null 2>&1; then
        return 1
    fi
    tmp=$(mktemp) || return 1
    # Only stdout (JSON) to file; stderr (warnings) to /dev/null so JSON stays valid
    imunify360-agent version --json >"$tmp" 2>/dev/null || { rm -f "$tmp"; return 1; }
    id=$(python3 -c "
import json, sys
try:
    with open(sys.argv[1]) as f:
        d = json.load(f)
    lid = (d.get('license') or {}).get('id') or ''
    if lid:
        print(lid)
except Exception:
    pass
" "$tmp" 2>/dev/null)
    rm -f "$tmp"
    if [ -n "$id" ]; then
        echo "$id"
        return 0
    fi
    return 1
}

get_distro_name() {
    local os_release_path="/etc/os-release"
    log "Get OS info... "
    if [ ! -f "$os_release_path" ]; then
        log "Error (Could not determine OS: $os_release_path does not exist)"
        return 1
    fi
    . "$os_release_path"
    if [ -z "$ID" ]; then
        log "Error (Could not determine OS: ID not found in $os_release_path)"
        return 1
    fi
    echo "$ID"
    return 0
}

# Determine the host architecture and set the architecture-specific package
# URIs. Uses dpkg's architecture name (amd64/arm64), which matches the .deb
# filename suffixes published in the repository.
detect_arch() {
    log "Detecting system architecture... "
    if ! command -v dpkg >/dev/null 2>&1; then
        log "Error (dpkg not found; cannot determine architecture)"
        return 1
    fi
    local arch
    arch=$(dpkg --print-architecture 2>/dev/null)
    case "$arch" in
        amd64|arm64)
            log "Detected architecture: $arch"
            ALT_COMMON_PACKAGE_URI="${ALT_COMMON_BASE_URI}.${arch}.deb"
            PACKAGE_URI="${PHP_RELEASE_BASE_URI}.${arch}.deb"
            return 0
            ;;
        "")
            log "Error (Could not determine architecture via 'dpkg --print-architecture')"
            return 1
            ;;
        *)
            log "Error (Unsupported architecture: $arch; only amd64 and arm64 are available)"
            return 1
            ;;
    esac
}

els_installed() {
    log "Checking if els-php-release is already installed... "
    if dpkg -l els-php-release >/dev/null 2>&1; then
        log "els-php-release package is already installed."
        return 0
    fi
    log "els-php-release package is not installed"
    return 1
}

extract_token() {
    # Case 1: clients use old way
    token=$(sed -n 's|.*php-els/\([^/]*\)/.*|\1|p' "$PHP_REPO_PATH")

    if [ -z "$token" ] || case "$token" in *SERVER*) false;; *) true;; esac; then
        log "Couldn't extract token from $PHP_REPO_PATH, trying from $AUTH_CONF_PATH"
        # Case 2: clients use new way (CLN token or Imunify360 license id)
        token=$(sed -n 's/^login \([^[:space:]]*\).*/\1/p' "$AUTH_CONF_PATH")
        if [ -z "$token" ]; then
            log "Couldn't extract token from $AUTH_CONF_PATH"
            return 1
        fi
    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
        echo "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
            echo "DELETE: elstoken wasn't found. Server is not registered"
        elif echo "$response" | grep -qi "wasn't found\|not registered"; then
            # Token was not registered in CLN (e.g. Imunify360 license id) — allow delete to proceed
            echo "Token not registered in CLN; proceeding with removal"
            return 0
        else
            echo "Got incorrect status from CLN: $response"
        fi
        return 1
    fi

    echo "Unregistered successfully"
    return 0
}

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

    log "PHP ELS deleted successfully"
    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
}

delete_els() {
    if els_installed; 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
}

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
}

install_alt_common_release() {
    log "Checking if alt-common-release is already installed... "
    if dpkg -l alt-common-release >/dev/null 2>&1; then
        log "alt-common-release package is already installed."
        return 0
    fi
    log "Installing alt-common-release..."

    ALT_COMMON_TEMP_DEB=$(mktemp /tmp/alt-common-releaseXXXXXX.deb)

    if ! curl -fsSL -o "$ALT_COMMON_TEMP_DEB" "$ALT_COMMON_PACKAGE_URI"; then
        log "Error: Couldn't download alt-common-release.deb"
        return 1
    fi

    if ! dpkg -i "$ALT_COMMON_TEMP_DEB"; then
        log "Error: Couldn't install alt-common-release"
        return 3
    fi

    return 0
}

install_els_php_release() {
    if ! install_alt_common_release; then
        return 2
    fi
    log "Installing els-php-release..."

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

    trap 'rm -f "$TEMP_DEB"' EXIT

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

    if ! dpkg -i "$TEMP_DEB"; then
        log "Error: Couldn't install els-php-release"
        return 3
    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

    distro=$(get_distro_name)
    if [ "$distro" != "debian" ] && [ "$distro" != "ubuntu" ]; then
        log "Detected unsupported distro: $distro"
        return 11
    fi

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

    if els_installed; then
        if [ "$FORCE" = "true" ]; then
            unregister_token
            remove_els
        else
            log "This server has installed ELS repo and token"
            log "For re-registration license run script with --force"
            return 2
        fi
    fi

    if ! detect_arch; then
        return 15
    fi

    local token
    if [ "$IMUNIFY" = "true" ]; then
        log "Using Imunify360 license for repository access..."
        token=$(get_imunify_license_id)
        if [ -z "$token" ]; then
            log "Error: Imunify360 is not installed on this system or has no valid license."
            log "Install Imunify360 with a valid license, or use --license-key for standard installation."
            return 1
        fi
        log "Ok"
    else
        log "Registering in CLN..."
        if ! token=$(get_auth_token "$CLN_REGISTER_SERVER" "$HOSTNAME" "$LICENSE"); then
            return 3
        fi
    fi

    if ! printf 'machine repo.alt.tuxcare.com/alt-php-els/\nlogin %s\npassword\n' "$token" > "$AUTH_CONF_PATH"; then
        log "Error (Could not write to $AUTH_CONF_PATH)"
        return 10
    fi

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

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

    log "ELS for PHP installed successfully"
}

main "$@"
