#!/bin/bash
# Script:      live-build-astra
# Title:       Astra Linux Live Build Configuration Generator
# Description: A script to generate and validate the configuration file for astra-live.
#              This script processes command-line arguments and creates a config file
#              for building a bootable Astra Linux image.

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

MAIN_EXECUTABLE="live-build-astra"

# The purpose of these variables is described in the help for the toggle_shell_options function in libastralive.
SET_E=""
SET_U=""

SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
export TEXTDOMAIN="live-build-astra"

# ----[ LIBRARY SOURCING ]----
for DIR in "${SCRIPT_DIR}" "/usr/lib/astra-live"; do
    if [ -f "${DIR}/libastralive" ]; then
        LIBASTRALIVE="${DIR}/libastralive"
        break
    fi
done
. "${LIBASTRALIVE}" || exit 1

# ----[ INTERNAL FUNCTIONS ]----
help() {
    console_colors
    echo -e "${CYAN}$(gettext "Usage:") $(basename $0) [OPTIONS]${ENDCOLOR}"
    echo "$(gettext "Creates a system image with the specified parameters.")"
    echo ""
    echo -e "${CYAN}$(gettext "Options:")${ENDCOLOR}"
    echo ""
    echo -e "${LIGHTBLUE}$(gettext "Config Options:")${ENDCOLOR}"
    echo -e "  ${LIGHTGREEN}--config-file${ENDCOLOR} FILE                 $(gettext "Specify the configuration file path. All other options are ignored.")"
    echo -e "  ${LIGHTGREEN}--config-only${ENDCOLOR}                      $(gettext "Generate the configuration file only and do not start the build process.")"
    #echo -e "  ${LIGHTGREEN}--config-strip${ENDCOLOR}                     $(gettext "Generate a stripped configuration file by removing comments and empty lines. This option is used in conjunction with --config-only.")"
    echo ""
    echo -e "${LIGHTBLUE}$(gettext "System Options:")${ENDCOLOR}"
    echo -e "  ${LIGHTGREEN}-nal, --no-autologin${ENDCOLOR}               $(gettext "Disable automatic login to system (used for Fly GUI only).")"
    echo -e "  ${LIGHTGREEN}-hn, --host-name${ENDCOLOR} HOST_NAME         $(gettext "Specify the host name for the system (default: astra).")"
    echo -e "  ${LIGHTGREEN}-un, --user-name${ENDCOLOR} USER_NAME         $(gettext "Specify the user name for the system (default: astra-live).")"
    echo -e "  ${LIGHTGREEN}-up, --user-password${ENDCOLOR} PASSWORD      $(gettext "Specify the user password for the system. The password will be hashed and stored securely. If both the password and hash are provided, the hash will override the password.")"
    echo -e "  ${LIGHTGREEN}-uph, --user-password-hash${ENDCOLOR} HASH    $(gettext "Specify the hashed user password (use 'echo \"P@ssw0rd\" | mkpasswd -s'). If both the password and hash are provided, the hash will override the password.")"
    echo ""
    echo -e "${LIGHTBLUE}$(gettext "Build Options:")${ENDCOLOR}"
    echo -e "  ${LIGHTGREEN}-b, --build-dir${ENDCOLOR} DIRECTORY          $(gettext "Specify the build directory (default: ./build)")"
    echo -e "  ${LIGHTGREEN}-c, --compression${ENDCOLOR} TYPE             $(gettext "Specify the compression type (default: zstd).")"
    echo -e "  ${LIGHTGREEN}-d, --distribution${ENDCOLOR} NAME            $(gettext "Specify the distribution code name (default: the distribution on which live-build-astra is running).")"
    echo -e "  ${LIGHTGREEN}-rs, --remove-sources${ENDCOLOR}              $(gettext "Remove all contents of the build directory before starting the build.")"
    echo -e "  ${LIGHTGREEN}-kc, --keep-cache${ENDCOLOR}                  $(gettext "Used in conjunction with --remove-sources. If specified, the apt cache is not removed from the build directory.")"
    echo -e "  ${LIGHTGREEN}-ki, --keep-image${ENDCOLOR}                  $(gettext "Used in conjunction with --remove-sources. If specified, the built image files are not removed from the build directory.")"
    echo -e "  ${LIGHTGREEN}-kl, --keep-log${ENDCOLOR}                    $(gettext "Used in conjunction with --remove-sources. Keep the log file after the build process.")"
    echo ""
    echo -e "${LIGHTBLUE}$(gettext "Repository Options:")${ENDCOLOR}"
    echo -e "  ${LIGHTGREEN}-r, -u, --repository${ENDCOLOR} FILE/DIR/URL  $(gettext "Specify the names of images/directories and(or) URLs (defaults to the built-in repository lists, if they exist).")"
    echo -e "  ${LIGHTGREEN}-ksl, --keep-sources-list${ENDCOLOR}          $(gettext "Keep the list of repositories provided to the -r/--repository option (by default, sources.list is replaced with the default for the distribution after the build is complete).")"
    echo ""
    echo -e "${LIGHTBLUE}$(gettext "Package Management:")${ENDCOLOR}"
    echo -e "  ${LIGHTGREEN}-ap, --add-packages${ENDCOLOR} PACKAGE        $(gettext "Add packages to the default list or tasksel task list. Packages can be from the repository, local packages, or local directories containing packages.")"
    echo -e "  ${LIGHTGREEN}-apl, --add-packages-list${ENDCOLOR} LIST     $(gettext "Add a list of packages to the default list or tasksel task list.")"
    echo -e "  ${LIGHTGREEN}-dp, --delete-packages${ENDCOLOR} PACKAGE     $(gettext "Delete packages from the default package list or tasksel task list.")"
    echo -e "  ${LIGHTGREEN}-dpl, --delete-packages-list${ENDCOLOR} LIST  $(gettext "Delete a list of packages from default package list or tasksel task list.")"
    echo -e "  ${LIGHTGREEN}-rp, --replace-packages${ENDCOLOR} PACKAGE    $(gettext "Replace the default package list with the specified packages.")"
    echo -e "  ${LIGHTGREEN}-rpl, --replace-packages-list${ENDCOLOR} LIST $(gettext "Replace the default package list with the specified list of packages.")"
    echo -e "  ${LIGHTGREEN}-t, --tasks${ENDCOLOR} TASK                   $(gettext "Replace the default package list with tasksel tasks.")"
    echo ""
    echo -e "${LIGHTBLUE}$(gettext "Output Options:")${ENDCOLOR}"
    echo -e "  ${LIGHTGREEN}-i, --iso${ENDCOLOR} NAME                     $(gettext "Generate an ISO disk image with the specified name (default: livecd-DD.MM.YY_HH.MM.iso). If no option is specified, this one is used by default.")"
    echo -e "  ${LIGHTGREEN}-R, --raw${ENDCOLOR} NAME                     $(gettext "Generate a raw disk image with the specified name (default: raw-DD.MM.YY_HH.MM.img).")"
    echo -e "  ${LIGHTGREEN}-q, --qcow2${ENDCOLOR} NAME                   $(gettext "Generate a QCOW2 virtual disk image with the specified name (default: qcow2-DD.MM.YY_HH.MM.qcow2).")"
    #echo -e "  ${LIGHTGREEN}-V, --vmdk${ENDCOLOR} NAME                    $(gettext "Generate a VMDK virtual disk image with the specified name (default: vmdk-DD.MM.YY_HH.MM.vmdk).")"
    echo -e "  ${LIGHTGREEN}-T, --tar${ENDCOLOR} NAME                     $(gettext "Generate a tarball archive with the specified name (default: tarball-DD.MM.YY_HH.MM.tar).")"
    echo -e "  ${LIGHTGREEN}-D, --docker${ENDCOLOR} NAME                  $(gettext "Generate a Docker container archive with the specified name (default: docker-DD.MM.YY_HH.MM.tar).")"
    echo -e "  ${LIGHTGREEN}-w, --wsl${ENDCOLOR} NAME                     $(gettext "Generate a WSL distribution archive with the specified name (default: wsl-DD.MM.YY_HH.MM.tar).")"
    echo ""
    echo -e "${LIGHTBLUE}$(gettext "Help Options:")${ENDCOLOR}"
    echo -e "  ${LIGHTGREEN}-h, --help${ENDCOLOR}                         $(gettext "Display this help and exit.")"
    echo -e "  ${LIGHTGREEN}-v, --version${ENDCOLOR}                      $(gettext "Display version information and exit.")"
    echo ""
    echo -e "${LIGHTBLUE}$(gettext "Examples:")${ENDCOLOR}"
    echo -e "  ${CYAN}$(basename $0)${ENDCOLOR} --build-dir /tmp/astra-live --compression lz4 --distribution 1.7_x86-64 --iso --url-list \"https://download.astralinux.ru/astra/stable/1.7_x86-64/repository-main,https://download.astralinux.ru/astra/stable/1.7_x86-64/repository-base,https://download.astralinux.ru/astra/stable/1.7_x86-64/repository-extended\""
    echo -e "  ${CYAN}$(basename $0)${ENDCOLOR} -c zstd -d 1.7_x86-64 -r https://download.astralinux.ru/astra/stable/1.7_x86-64/repository-main https://download.astralinux.ru/astra/stable/1.7_x86-64/repository-base -i astra-live.iso -t Base Fly -dp mc synaptic"
    exit 0
}

brief_help() {
    echo "Usage: $(basename $0) [OPTIONS]"
    echo "Try '$(basename $0) --help' for more information."
    exit 1
}

# ----[ COMMON SETUP ]----
console_colors  # Set console colors
allow_root_only # Allow only root user to run the script

toggle_shell_options e
while (("${#}")); do
    case "${1}" in
    --config-file)
        CONFIG_FILE="${2}"
        shift 2
        ;;
    --config-only)
        CONFIG_ONLY="true"
        shift
        ;;
    --config-strip)
        CONFIG_STRIP="true"
        shift
        ;;
    -nal | --no-autologin)
        AUTOLOGIN="false"
        shift
        ;;
    -ap | --add-packages)
        process_flag "check" "array" "ADD_PACKAGES" "${@}"
        shift "$?"
        ;;
    -apl | --add-packages-list)
        process_flag "check" "string" "ADD_PACKAGES_LIST" "${@}"
        shift "$?"
        ;;
    -b | --build-dir)
        process_flag "check" "string" "BUILD_DIR" "${@}"
        shift "$?"
        ;;
    -c | --compression)
        process_flag "check" "string" "COMP_TYPE" "${@}"
        shift "$?"
        ;;
    -d | --distribution)
        process_flag "check" "string" "DISTRIBUTION" "${@}"
        shift "$?"
        ;;
    -D | --docker)
        GENERATE_IMAGES+=("docker")
        process_flag "skip" "string" "DOCKER_NAME" "${@}"
        shift "$?"
        ;;
    -dp | --delete-packages)
        process_flag "check" "array" "DELETE_PACKAGES" "${@}"
        shift "$?"
        ;;
    -dpl | --delete-packages-list)
        process_flag "check" "string" "DELETE_PACKAGES_LIST" "${@}"
        shift "$?"
        ;;
    -hn | --host-name)
        process_flag "check" "string" "HOST_NAME" "${@}"
        shift "$?"
        ;;
    -i | --iso)
        GENERATE_IMAGES+=("iso")
        process_flag "skip" "string" "ISO_NAME" "${@}"
        shift "$?"
        ;;
    -kc | --keep-cache)
        KEEP_CACHE="true"
        shift
        ;;
    -ki | --keep-image)
        KEEP_IMAGE="true"
        shift
        ;;
    -kl | --keep-log)
        KEEP_LOG="true"
        shift
        ;;
    -q | --qcow2)
        GENERATE_IMAGES+=("qcow2")
        process_flag "skip" "string" "QCOW2_NAME" "${@}"
        shift "$?"
        ;;
    -R | --raw)
        GENERATE_IMAGES+=("raw")
        process_flag "skip" "string" "RAW_NAME" "${@}"
        shift "$?"
        ;;
    -r | -u | --repository)
        process_flag "check" "array" "REPO_LIST" "${@}"
        shift "$?"
        ;;
    -ksl | --keep-sources-list)
        KEEP_SOURCES_LIST="true"
        shift
        ;;
    -rp | --replace-packages)
        process_flag "check" "array" "REPLACE_PACKAGES" "${@}"
        shift "$?"
        ;;
    -rpl | --replace-packages-list)
        process_flag "check" "string" "REPLACE_PACKAGES_LIST" "${@}"
        shift "$?"
        ;;
    -rs | --remove-sources)
        REMOVE_SOURCES="true"
        shift
        ;;
    -T | --tar)
        GENERATE_IMAGES+=("tar")
        process_flag "skip" "string" "TAR_NAME" "${@}"
        shift "$?"
        ;;
    -t | --tasks)
        process_flag "check" "array" "TASKS" "${@}"
        shift "$?"
        ;;
    -un | --user-name)
        process_flag "check" "string" "USER_NAME" "${@}"
        shift "$?"
        ;;
    -up | --user-password)
        process_flag "check" "string" "USER_PASSWORD" "${@}"
        shift "$?"
        USER_PASSWORD_HASH=$(echo "${USER_PASSWORD}" | mkpasswd -s)
        ;;
    -uph | --user-password-hash)
        process_flag "check" "string" "USER_PASSWORD_HASH" "${@}"
        shift "$?"
        ;;
    # vmdk image is built by converting from qcow2, at the same time, conversion breaks the bootloader, so it was decided to remove the ability to build vmdk.
    #-V | --vmdk)
    #    GENERATE_IMAGES+=("vmdk")
    #    process_flag "skip" "string" "VMDK_NAME" "${@}"
    #    shift "$?"
    #    ;;
    -w | --wsl)
        GENERATE_IMAGES+=("wsl")
        process_flag "skip" "string" "WSL_NAME" "${@}"
        shift "$?"
        ;;
    -h | --help)
        help
        ;;
    -v | --version)
        version
        ;;
    --)
        shift
        break
        ;;
    -* | --*)
        error "Unsupported flag ${1}"
        brief_help
        ;;
    *)
        error "Invalid input ${1}"
        brief_help
        ;;
    esac
done
toggle_shell_options e

set_variables BUILD_DIR="${PWD}/build" # If the variable has not been set before, assign a value to it

if [ "${CONFIG_ONLY}" != "true" ]; then
    trap 'unmount_dirs ${BUILD_DIR}; stop_http_server' EXIT
fi

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

CONFIG_PATH="${BUILD_DIR}/config"

[ -n "${CONFIG_FILE}" ] && CONFIG_FILE=$(realpath "${CONFIG_FILE}")

copy_and_validate_config() {
    local SRC=$1
    local DEST=$2

    mkdir -p "$(dirname "${DEST}")"
    cp "${SRC}" "${DEST}"
    if bash -n "${DEST}"; then
        [ "${CONFIG_STRIP}" == "true" ] && sed -i '/^\s*#/d;/^\s*$/d' "${DEST}"
        update_config "${DEST}"
        information "Configuration file has been generated successfully at ${CYAN}${DEST}${ENDCOLOR}."
        grant_write_permissions "${DEST}"
    else
        error "The configuration file ${CYAN}${DEST}${ENDCOLOR} contains syntax errors. Please make the necessary changes and try again."
        exit 1
    fi
}

handle_config_only() {
    local CONFIG_TARGET=$1
    mkdir -p "$(dirname "${CONFIG_TARGET}")"
    if [ -f "${SCRIPT_DIR}/config" ]; then
        copy_and_validate_config "${SCRIPT_DIR}/config" "${CONFIG_TARGET}"
    else
        copy_and_validate_config "/etc/astra-live/config" "${CONFIG_TARGET}"
    fi
    exit 0
}

if [ "${CONFIG_ONLY}" == "true" ]; then
    handle_config_only "${CONFIG_FILE:-${CONFIG_PATH}}"
fi

if [ -n "${CONFIG_FILE}" ] && [ ! -f "${CONFIG_FILE}" ]; then
    error "The configuration file ${CYAN}${CONFIG_FILE}${ENDCOLOR} does not exist. Please provide a valid configuration file."
    exit 1
fi

mkdir -p "${BUILD_DIR}"
if [ -n "${CONFIG_FILE}" ] && [ -f "${CONFIG_FILE}" ]; then
    copy_and_validate_config "${CONFIG_FILE}" "${CONFIG_PATH}"
else
    if [ -f "${SCRIPT_DIR}/config" ]; then
        copy_and_validate_config "${SCRIPT_DIR}/config" "${CONFIG_PATH}"
    else
        copy_and_validate_config "/etc/astra-live/config" "${CONFIG_PATH}"
    fi
fi

BUILD_DIR="${BUILD_DIR}" \
    MAIN_EXECUTABLE="${MAIN_EXECUTABLE}" \
    "${SCRIPT_DIR}/astra-live" -
