#!/bin/bash
# Script:      astra-live
# Title:       Astra Linux Live Build Orchestrator
# Description: This script orchestrates the build process for a bootable Astra Linux image.
#              It reads the configuration, sets up the environment, installs packages, and
#              creates the final image in the specified format.

# ----[ HEADER AND DEFINITIONS ]----
set -e          # exit on error
set -o pipefail # exit on pipeline error
set -u          # treat unset variable as error

SCRIPT_PATH="$0"
if [[ "$0" != */* ]]; then
    SCRIPT_PATH="$(which "$0")"
else
    SCRIPT_PATH="$(readlink -f "$0")"
fi
SCRIPT_ARGS="$*"
ORIGINAL_PWD="${ORIGINAL_PWD:-${PWD}}"
export SCRIPT_PATH SCRIPT_ARGS ORIGINAL_PWD
SCRIPT_DIR="$(dirname "$(readlink -f "${SCRIPT_PATH}")")"
export TEXTDOMAIN="live-build-astra"

# ----[ PATH INITIALIZATION ]----
initialize_paths() {
    # Determine if running from source directory or system installation based on SCRIPT_DIR
    if [[ "${SCRIPT_DIR}" == "/usr/bin" ]]; then
        # System installation in /usr
        local PREFIX="/usr"
    elif [[ "${SCRIPT_DIR}" == "/usr/local/bin" ]]; then
        # System installation in /usr/local
        local PREFIX="/usr/local"
    else
        # Running from source directory
        export PACKAGES_DIR="${SCRIPT_DIR}/packages"
        export SOURCES_DIR="${SCRIPT_DIR}/sources"
        export ROOTCOPY_DIR="${SCRIPT_DIR}/rootcopy"
        export HOOKS_DIR="${SCRIPT_DIR}/hooks"
        export SCRIPTS_DIR="${SCRIPT_DIR}/scripts"
        export LIBASTRALIVE="${SCRIPT_DIR}/libastralive"
        return
    fi

    # System installation paths
    export PACKAGES_DIR="/usr/share/astra-live/packages"
    export SOURCES_DIR="/usr/share/astra-live/sources"
    export ROOTCOPY_DIR="/usr/share/astra-live/rootcopy"
    export HOOKS_DIR="/usr/share/astra-live/hooks"
    export SCRIPTS_DIR="/usr/share/astra-live/scripts"
    export LIBASTRALIVE="${PREFIX}/lib/astra-live/libastralive"
}

# Initialize paths only if not called from live-build-astra
[ "${MAIN_EXECUTABLE:-}" != "live-build-astra" ] && initialize_paths

# ----[ LIBRARY SOURCING ]----
. "${LIBASTRALIVE}" || exit 1

console_colors # Set console colors
# Initialize paths if not already done by parent script

# ----[ INTERNAL FUNCTIONS ]----
help() {
    local HEADLINE="${1:-$(gettext 'This script builds a bootable Astra Linux image.')}"
    local COMMANDS="${CMD[*]//_/-}"
    local SYNTAX="$0 [start_cmd] [-] [end_cmd]"
    local EXAMPLES=(
        "${LIGHTYELLOW}  $0 -                                ${ENDCOLOR}$(gettext "Run the build from start to finish.")"
        "${LIGHTYELLOW}  $0 build-environment - build-chroot ${ENDCOLOR}$(gettext "Start the build by building the base environment and finish by installing the entire system in chroot.")"
        "${LIGHTYELLOW}  $0 - build-chroot                   ${ENDCOLOR}$(gettext "Start the build from the beginning and finish by installing the entire system in chroot.")"
        "${LIGHTYELLOW}  $0 build-environment -              ${ENDCOLOR}$(gettext "Start the build by building the base environment and run to completion.")"
        "${LIGHTYELLOW}  $0 build-image                      ${ENDCOLOR}$(gettext "Build only images from previously prepared data.")"
    )

    echo -e "${LIGHTYELLOW}${HEADLINE}${ENDCOLOR}\n"
    echo -e "$(gettext "Supported commands:") ${CYAN}${COMMANDS[*]}${ENDCOLOR}\n"
    echo -e "$(gettext "Usage:") ${MAGENTA}${SYNTAX}${ENDCOLOR}"
    echo -e "$(gettext "  Run from start_cmd to end_cmd")"
    echo -e "$(gettext "  If start_cmd is omitted, start from the first command")"
    echo -e "$(gettext "  If end_cmd is omitted, end with the last command")"
    echo -e "$(gettext "  Enter a single cmd to run the specific command")"
    echo -e "$(gettext "  Enter '-' as the only argument to run all commands\n")"
    echo -e "$(gettext "Interactive Features:")"
    echo -e "$(gettext "  During quiet build operations (VERBOSITY_LEVEL=0), press 'r' to toggle")"
    echo -e "$(gettext "  between spinner mode and real-time output mode\n")"
    echo -e "$(gettext "Examples:")"
    for EXAMPLE in "${EXAMPLES[@]}"; do
        echo -e "${EXAMPLE}"
    done

    exit 0
}

# ----[ COMMON SETUP ]----
set +u
set_variables BUILD_DIR="${ORIGINAL_PWD}/build" # If the variable has not been set before, assign a value to it
set_variables MAIN_EXECUTABLE="astra-live"      # If the variable has not been set before, assign a value to it

# Normalize BUILD_DIR path if it's relative (before allow_root_only call)
if [[ -n "${BUILD_DIR:-}" ]] && [[ "${BUILD_DIR}" != /* ]]; then
    BUILD_DIR="${ORIGINAL_PWD}/${BUILD_DIR}"
fi

set -u
console_colors # Set console colors

CMD=(build_environment build_bootstrap build_chroot build_live build_boot build_image) # CMD holds a list of available commands that can be executed by the build script.

# normalize both hyphens and underscores into underscore form,
# but leave lone "-" untouched
ARGS=("$@")
for idx in "${!ARGS[@]}"; do
    [[ "${ARGS[$idx]}" == "-" ]] && continue
    ARGS[$idx]="${ARGS[$idx]//-/_}"
done
set -- "${ARGS[@]}"

process_command_range "$@" # Process script arguments to define the range of commands to execute.

# Allow only root user to run the script (after help/version checks)
allow_root_only

# Create log file and setup environment after getting root privileges
create_log_file "$@" # Сreate a log file to record script output
INSTALL_DIR="${INSTALL_DIR:-${BUILD_DIR}/chroot}"

trap 'unmount_dirs ${BUILD_DIR}; stop_http_server' EXIT

if [ ! -f "${BUILD_DIR}/config" ]; then
    if [ -f "${SCRIPT_DIR}/config" ]; then
        cp "${SCRIPT_DIR}/config" "${BUILD_DIR}/config"
    else
        cp "/etc/astra-live/config" "${BUILD_DIR}/config"
    fi
fi

if check_config_file "${BUILD_DIR}/config" REMOVE_SOURCES KEEP_CACHE KEEP_IMAGE KEEP_LOG; then
    read_config "${BUILD_DIR}/config" REMOVE_SOURCES KEEP_CACHE KEEP_IMAGE KEEP_LOG
else
    exit 1
fi

set +u
# If the first command in the queue is 'build_environment', then if REMOVE_SOURCES="true", remove_sources clears the build directory.
if [ "${CMD[INDEX]}" = "build_environment" ]; then
    remove_sources
fi

set -u
if check_config_file "${BUILD_DIR}/config" DISTRIBUTION ARCHITECTURE HOST_NAME USER_NAME USER_PASSWORD_HASH AUTOLOGIN BUILD_DIR COMP_TYPE REMOVE_SOURCES KEEP_CACHE KEEP_IMAGE KEEP_LOG REPO_LIST ADD_PACKAGES ADD_PACKAGES_LIST DELETE_PACKAGES DELETE_PACKAGES_LIST REPLACE_PACKAGES REPLACE_PACKAGES_LIST TASKS SIMULATION_MODE VERBOSITY_LEVEL GENERATE_IMAGES ISO_NAME DOCKER_NAME DOCKER_TAG QCOW2_NAME RAW_NAME TAR_NAME VMDK_NAME WSL_NAME; then
    . "${BUILD_DIR}/config"
    grant_write_permissions "${BUILD_DIR}/config"

    # Convert relative paths from config to absolute paths relative to ORIGINAL_PWD
    if [[ -n "${BUILD_DIR:-}" ]] && [[ "${BUILD_DIR}" != /* ]]; then
        BUILD_DIR="${ORIGINAL_PWD}/${BUILD_DIR}"
    fi

    if [[ -n "${ADD_PACKAGES_LIST:-}" ]] && [[ "${ADD_PACKAGES_LIST}" != /* ]]; then
        ADD_PACKAGES_LIST="${ORIGINAL_PWD}/${ADD_PACKAGES_LIST}"
    fi

    if [[ -n "${DELETE_PACKAGES_LIST:-}" ]] && [[ "${DELETE_PACKAGES_LIST}" != /* ]]; then
        DELETE_PACKAGES_LIST="${ORIGINAL_PWD}/${DELETE_PACKAGES_LIST}"
    fi

    if [[ -n "${REPLACE_PACKAGES_LIST:-}" ]] && [[ "${REPLACE_PACKAGES_LIST}" != /* ]]; then
        REPLACE_PACKAGES_LIST="${ORIGINAL_PWD}/${REPLACE_PACKAGES_LIST}"
    fi
else
    exit 1
fi

export VERBOSITY_LEVEL
export SHOW_SPINNER_OUTPUT

check_required_packages # Check if the required packages are present

set +u
set_variables DOCKER_TAG="astralinux:${DISTRIBUTION}"
update_config "${BUILD_DIR}/config" DOCKER_TAG GENERATE_IMAGES BUILD_DIR
set -u

# ----[ MAIN ]----

export LC_ALL=C

# Run commands within the defined range.
for ((ITERATOR = "${START_INDEX}"; ITERATOR < "${END_INDEX}"; ITERATOR++)); do
    "${CMD[ITERATOR]}"
done
