#!/bin/bash
SOURCE="$0"
source /usr/lib/elive-tools/functions
if el_check_version_is_days_recent 120; then
    export FORCE_REPORTS="1"
    export NOREPORTS="0"
    export EL_REPORTS="1"
else
    export FORCE_REPORTS="0"
    export NOREPORTS="1"
    export EL_REPORTS="0"
fi
el_make_environment

if [[ -z "${yad:-}" ]]; then
    yad="/usr/bin/yad --borders=15 --center --image=logo-elive"
fi

#===  FUNCTION  ================================================================
#          NAME:  locales_source
#   DESCRIPTION:  Sources default locales and normalizes non-Latin locale settings
#    PARAMETERS:  None
#       RETURNS:  0
#===============================================================================
locales_source(){
    if [[ -s "/etc/default/locale" ]] ; then
        source /etc/default/locale
    fi
    case "${LANG}" in
        am*|ar*|bg*|bn*|el*|fa*|gu*|he*|hy*|hi*|iw*|ja*|ka*|kn*|ko*|ml*|mr*|ne*|pa*|ru*|sr*|ta*|te*|th*|uk*|vi*|zh*)
            export LC_ALL=en_US.UTF-8
            export LANG=en_US.UTF-8
            ;;
    esac
    return 0
}
locales_source

. gettext.sh
TEXTDOMAIN="elive-upgrader"
export TEXTDOMAIN

#
# elive-boot-upgrader - Handles boot-time Debian distribution upgrades
#
set -e

source /usr/lib/elive-tools/functions 2>/dev/null || true
source /usr/lib/elive-upgrader/functions.sh 2>/dev/null || true

export LANG="${EL_LC_EN}"
export TERM="linux"

if [[ -f "${hooks_d}/distro-upgrade/debian-upgrade" ]]; then
    _upgrade_type="$(tr -d '\r\n ' < "${hooks_d}/distro-upgrade/debian-upgrade")"
    if [[ "${_upgrade_type}" == "alpha" ]]; then
        export FORCE_REPORTS="1"
    fi
fi

if ! command -v el_error &>/dev/null; then
    el_error() { echo "ERROR: $*" >&2; }
fi
if ! command -v el_warning &>/dev/null; then
    el_warning() { echo "WARNING: $*" >&2; }
fi

DEFAULTS_FILE="/etc/default/elive-distro-upgrade"
LOCK_FILE="/tmp/.debian-upgrader.lock"
SCRIPT_PATH="/usr/lib/elive-upgrader/debian-upgrader"

#===  FUNCTION  ================================================================
#          NAME:  get_current_codename
#   DESCRIPTION:  Retrieves the current Debian codename from /etc/debian_version
#    PARAMETERS:  None
#       RETURNS:  Prints the Debian codename string
#===============================================================================
get_current_codename(){
    source /usr/lib/elive-tools/functions 2>/dev/null || true
    local current_release_full_v=""
    local current_version_number_v=""

    current_release_full_v="$(cat /etc/debian_version 2>/dev/null || echo "unknown")"
    current_version_number_v="$(echo "${current_release_full_v}" | cut -d'.' -f1)"
    debian_version_to_codename "${current_version_number_v}"
}

#===  FUNCTION  ================================================================
#          NAME:  upgrade_check_target_reached
#   DESCRIPTION:  Checks if system has reached the specified target codename
#    PARAMETERS:  $1 = target_codename_v
#       RETURNS:  0 if target reached, 1 otherwise
#===============================================================================
upgrade_check_target_reached(){
    local target_codename_v="${1}"
    local current_codename_v=""

    current_codename_v="$(get_current_codename)"

    if [[ -n "${current_codename_v}" ]] && [[ "${current_codename_v}" == "${target_codename_v}" ]]; then
        return 0
    fi
    return 1
}

#===  FUNCTION  ================================================================
#          NAME:  disable_boot_services
#   DESCRIPTION:  Disables boot upgrade services across systemd, sysvinit, and OpenRC
#    PARAMETERS:  None
#       RETURNS:  0
#===============================================================================
disable_boot_services(){
    if ((is_systemd)); then
        systemctl stop elive-distro-upgrader.service 2>/dev/null || true
        systemctl disable elive-distro-upgrader.service 2>/dev/null || true
        systemctl unmask getty@tty1.service 2>/dev/null || true
        systemctl daemon-reload 2>/dev/null || true
    elif ((is_openrc)); then
        rc-update del elive-distro-upgrader 2>/dev/null || true
    elif ((is_sysvinit)); then
        update-rc.d -f elive-distro-upgrader remove 2>/dev/null || true
    fi
    return 0
}

#===  FUNCTION  ================================================================
#          NAME:  suspend_tty1_and_dms
#   DESCRIPTION:  Suspends TTY1 getty login and stops display managers for clear console
#    PARAMETERS:  None
#       RETURNS:  0
#===============================================================================
suspend_tty1_and_dms(){
    local dm_v=""
    local srv_v=""
    local dm_list_v="display-manager lightdm gdm gdm3 sddm xdm slim nodm lxdm cdm"

    echo "Suspending TTY1 login and display managers..." >/dev/console 2>/dev/null || true

    mkdir -p /var/cache/elive-upgrader 2>/dev/null || true
    chmod 777 /var/cache/elive-upgrader 2>/dev/null || true
    local state_file_f="/var/cache/elive-upgrader/suspended-services.txt"

    if ((is_systemd)); then
        if ! systemctl is-masked --quiet getty@tty1.service 2>/dev/null; then
            if ! grep -qxF "SYSTEMD_MASKED:getty@tty1.service" "${state_file_f}" 2>/dev/null; then
                echo "SYSTEMD_MASKED:getty@tty1.service" >> "${state_file_f}"
            fi
            systemctl stop getty@tty1.service 2>/dev/null || true
            systemctl mask getty@tty1.service 2>/dev/null || true
        fi
        for dm_v in ${dm_list_v}; do
            if systemctl is-active --quiet "${dm_v}.service" 2>/dev/null; then
                if ! grep -qxF "SYSTEMD_ACTIVE:${dm_v}.service" "${state_file_f}" 2>/dev/null; then
                    echo "SYSTEMD_ACTIVE:${dm_v}.service" >> "${state_file_f}"
                fi
                systemctl stop "${dm_v}.service" 2>/dev/null || true
            elif systemctl is-enabled --quiet "${dm_v}.service" 2>/dev/null; then
                if ! grep -qxF "SYSTEMD_ENABLED:${dm_v}.service" "${state_file_f}" 2>/dev/null; then
                    echo "SYSTEMD_ENABLED:${dm_v}.service" >> "${state_file_f}"
                fi
                systemctl stop "${dm_v}.service" 2>/dev/null || true
            fi
        done
        systemctl stop display-manager.service 2>/dev/null || true
    elif ((is_openrc)); then
        for dm_v in ${dm_list_v}; do
            if rc-service "${dm_v}" status >/dev/null 2>&1; then
                if ! grep -qxF "OPENRC_ACTIVE:${dm_v}" "${state_file_f}" 2>/dev/null; then
                    echo "OPENRC_ACTIVE:${dm_v}" >> "${state_file_f}"
                fi
                echo "Stopping OpenRC display manager: ${dm_v}" >/dev/console 2>/dev/null || true
                rc-service "${dm_v}" stop 2>/dev/null || true
            fi
        done
        for srv_v in $(rc-status --all 2>/dev/null | grep -E "lightdm|gdm|sddm|xdm|slim|nodm|lxdm|display-manager" | awk '{print $1}'); do
            if ! grep -qxF "OPENRC_ACTIVE:${srv_v}" "${state_file_f}" 2>/dev/null; then
                echo "OPENRC_ACTIVE:${srv_v}" >> "${state_file_f}"
            fi
            rc-service "${srv_v}" stop 2>/dev/null || true
        done
        if rc-service getty.tty1 status >/dev/null 2>&1; then
            if ! grep -qxF "OPENRC_ACTIVE:getty.tty1" "${state_file_f}" 2>/dev/null; then
                echo "OPENRC_ACTIVE:getty.tty1" >> "${state_file_f}"
            fi
            rc-service getty.tty1 stop 2>/dev/null || true
        fi
    elif ((is_sysvinit)); then
        for dm_v in ${dm_list_v}; do
            if service "${dm_v}" status >/dev/null 2>&1; then
                if ! grep -qxF "SYSV_ACTIVE:${dm_v}" "${state_file_f}" 2>/dev/null; then
                    echo "SYSV_ACTIVE:${dm_v}" >> "${state_file_f}"
                fi
                service "${dm_v}" stop 2>/dev/null || true
            fi
        done
    fi

    pkill -f "lightdm|gdm|sddm|xdm|slim|nodm|lxdm|Xorg|Xwayland" 2>/dev/null || true

    if [[ -f /etc/inittab ]]; then
        if grep -qE '^[0-9]+:.*getty.*tty1' /etc/inittab 2>/dev/null; then
            if ! grep -qxF "INITTAB_TTY1:true" "${state_file_f}" 2>/dev/null; then
                echo "INITTAB_TTY1:true" >> "${state_file_f}"
            fi
            sed -i 's/^\([0-9]\+:.*getty.*tty1.*\)/#DISABLED-BY-UPGRADER#\1/' /etc/inittab 2>/dev/null || true
            telinit q 2>/dev/null || kill -HUP 1 2>/dev/null || true
        fi
    fi
    return 0
}

#===  FUNCTION  ================================================================
#          NAME:  restore_tty1_and_dms
#   DESCRIPTION:  Restores TTY1 getty login service after upgrade completion
#    PARAMETERS:  None
#       RETURNS:  0
#===============================================================================
restore_tty1_and_dms(){
    echo "Restoring TTY1 login and display manager configuration..." >/dev/console 2>/dev/null || true

    if command -v plymouth &>/dev/null && plymouth --ping &>/dev/null; then
        plymouth quit 2>/dev/null || true
    fi

    stty sane 2>/dev/null || true

    local state_file_f="/var/cache/elive-upgrader/suspended-services.txt"

    if [[ -f "${state_file_f}" ]]; then
        local entry_v=""
        while read -r entry_v || [[ -n "${entry_v}" ]]; do
            [[ -z "${entry_v}" ]] && continue
            local action_v="${entry_v%%:*}"
            local srv_v="${entry_v#*:}"

            case "${action_v}" in
                SYSTEMD_MASKED)
                    if ((is_systemd)); then
                        systemctl unmask "${srv_v}" 2>/dev/null || true
                    fi
                    ;;
                SYSTEMD_ACTIVE)
                    if ((is_systemd)); then
                        systemctl unmask "${srv_v}" 2>/dev/null || true
                        systemctl enable "${srv_v}" 2>/dev/null || true
                        systemctl start "${srv_v}" 2>/dev/null || true
                    fi
                    ;;
                SYSTEMD_ENABLED)
                    if ((is_systemd)); then
                        systemctl unmask "${srv_v}" 2>/dev/null || true
                        systemctl enable "${srv_v}" 2>/dev/null || true
                    fi
                    ;;
                OPENRC_ACTIVE)
                    if ((is_openrc)); then
                        rc-update add "${srv_v}" default 2>/dev/null || true
                        rc-service "${srv_v}" start 2>/dev/null || true
                    fi
                    ;;
                OPENRC_ENABLED)
                    if ((is_openrc)); then
                        rc-update add "${srv_v}" default 2>/dev/null || true
                    fi
                    ;;
                SYSV_ACTIVE)
                    if ((is_sysvinit)); then
                        update-rc.d "${srv_v}" defaults 2>/dev/null || true
                        service "${srv_v}" start 2>/dev/null || true
                    fi
                    ;;
                SYSV_ENABLED)
                    if ((is_sysvinit)); then
                        update-rc.d "${srv_v}" defaults 2>/dev/null || true
                    fi
                    ;;
            esac
        done < <(sort -u "${state_file_f}" 2>/dev/null || cat "${state_file_f}")
        rm -f "${state_file_f}" 2>/dev/null || true
    else
        if ((is_systemd)); then
            systemctl unmask getty@tty1.service 2>/dev/null || true
            systemctl unmask lightdm.service 2>/dev/null || true
            systemctl unmask display-manager.service 2>/dev/null || true
            systemctl enable lightdm.service 2>/dev/null || systemctl enable display-manager.service 2>/dev/null || true
        fi
    fi

    if ((is_systemd)); then
        systemctl daemon-reload 2>/dev/null || true
    fi

    # Reconfigure actual /etc/inittab in-place without replacing it with ancient backup files
    if [[ -f /etc/inittab ]]; then
        sed -i 's/^#DISABLED-BY-UPGRADER#//' /etc/inittab 2>/dev/null || true
        telinit q 2>/dev/null || kill -HUP 1 2>/dev/null || true
    fi
    rm -f /etc/inittab.bak-upgrader 2>/dev/null || true

    return 0
}

#===  FUNCTION  ================================================================
#          NAME:  process_remove_if_not_before
#   DESCRIPTION:  Processes post-upgrade package removal hooks for new packages
#    PARAMETERS:  $1 = target_codename_v
#       RETURNS:  0
#===============================================================================
process_remove_if_not_before(){
    local target_codename_v="${1}"
    local marker_file_f="/var/cache/elive-upgrader/remove-if-not-before-done"
    local pkgs_before_file_f="/var/log/elive-upgrader/debian-upgrade-packages-before-${target_codename_v}.txt"
    local pending_list_f="/var/cache/elive-upgrader/pending-remove-if-not-before.txt"
    local hook_file_f=""
    local pattern_v=""
    local expanded_pkgs_v=""
    local filtered_v=""
    local pkg_v=""
    local pkg_base_v=""
    local pkgs_to_remove_v=""
    local apt_exit_v=0

    if [[ -f "${marker_file_f}" ]]; then
        echo "remove-if-not-before check already completed previously, skipping."
        return 0
    fi

    if [[ ! -f "${pkgs_before_file_f}" ]]; then
        echo "No packages-before file found at ${pkgs_before_file_f}, skipping remove-if-not-before check."
        return 0
    fi

    if [[ ! -f "${pending_list_f}" ]]; then
        echo "No pending remove-if-not-before hooks found."
        return 0
    fi

    while read -r hook_file_f || [[ -n "${hook_file_f}" ]]; do
        [[ -z "${hook_file_f}" ]] && continue
        if [[ -f "${hook_file_f}" ]]; then
            echo "Processing remove-if-not-before hook: ${hook_file_f}"
            while read -r pattern_v || [[ -n "${pattern_v}" ]]; do
                [[ -z "${pattern_v}" ]] && continue
                case "${pattern_v}" in
                    \#*) continue ;;
                esac

                echo "DEBUG: Checking pattern '${pattern_v}' against packages-before file"

                expanded_pkgs_v="$(dpkg-query -W -f='${db:Status-Status} ${Package}\n' "${pattern_v}" 2>/dev/null | grep '^installed ' | cut -d' ' -f2- || true)"

                if [[ -z "${expanded_pkgs_v}" ]]; then
                    echo "DEBUG: dpkg-query returned no results, trying apt list fallback..."
                    expanded_pkgs_v="$(apt list --installed "${pattern_v}" 2>/dev/null | grep -v "^Listing" | cut -d'/' -f1 | grep -v "^$" || true)"
                    if [[ -n "${expanded_pkgs_v}" ]]; then
                        filtered_v=""
                        for pkg_v in ${expanded_pkgs_v}; do
                            if dpkg-query -W -f='${db:Status-Status}' "${pkg_v}" 2>/dev/null | grep -q '^installed'; then
                                filtered_v="${filtered_v} ${pkg_v}"
                            fi
                        done
                        expanded_pkgs_v="$(echo "${filtered_v}" | xargs)"
                    fi
                fi

                pkgs_to_remove_v=""
                if [[ -n "${expanded_pkgs_v}" ]]; then
                    for pkg_v in ${expanded_pkgs_v}; do
                        pkg_base_v="$(echo "${pkg_v}" | cut -d':' -f1)"
                        if ! grep -qxF "${pkg_v}" "${pkgs_before_file_f}" && ! grep -qxF "${pkg_base_v}" "${pkgs_before_file_f}"; then
                            echo "Package '${pkg_v}' was NOT present before upgrade. Adding to removal list."
                            pkgs_to_remove_v="${pkgs_to_remove_v} ${pkg_v}"
                        else
                            echo "Package '${pkg_v}' was present before upgrade. Keeping."
                        fi
                    done
                    pkgs_to_remove_v="$(echo "${pkgs_to_remove_v}" | xargs)"
                fi

                if [[ -n "${pkgs_to_remove_v}" ]]; then
                    echo "Removing packages: ${pkgs_to_remove_v}"
                    echo "Executing: TERM=linux DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical DEBCONF_NONINTERACTIVE_SEEN=true DEBCONF_NOWARNINGS=true apt-get -y -o Dpkg::Options::=\"--force-confdef\" -o Dpkg::Options::=\"--force-confold\" -o Dpkg::Options::=\"--force-overwrite\" --allow-downgrades --allow-remove-essential --allow-change-held-packages remove --purge ${pkgs_to_remove_v}"
                    TERM=linux DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=critical DEBCONF_NONINTERACTIVE_SEEN=true DEBCONF_NOWARNINGS=true apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -o Dpkg::Options::="--force-overwrite" --allow-downgrades --allow-remove-essential --allow-change-held-packages remove --purge ${pkgs_to_remove_v}
                    apt_exit_v=$?
                    if [[ "${apt_exit_v}" -ne 0 ]]; then
                        echo "WARNING: apt-get remove failed with exit code ${apt_exit_v} for packages: ${pkgs_to_remove_v}"
                    else
                        echo "Successfully removed packages: ${pkgs_to_remove_v}"
                    fi
                else
                    echo "No packages matching pattern '${pattern_v}' need to be removed."
                fi
            done < "${hook_file_f}"
        fi
    done < "${pending_list_f}"

    rm -f "${pending_list_f}"
    rm -rf /var/cache/elive-upgrader/active-distro-upgrade-hook 2>/dev/null || true
    mkdir -p "$(dirname "${marker_file_f}")"
    touch "${marker_file_f}"
    return 0
}

#===  FUNCTION  ================================================================
#          NAME:  cleanup_and_disable
#   DESCRIPTION:  Cleans up upgrade state files and disables boot upgrade services
#    PARAMETERS:  None
#       RETURNS:  0
#===============================================================================
cleanup_and_disable(){
    echo "Cleaning up upgrade state and disabling boot services"
    rm -f "${DEFAULTS_FILE}"
    rm -f "${LOCK_FILE}"
    disable_boot_services
    restore_tty1_and_dms
    return 0
}

#===  FUNCTION  ================================================================
#          NAME:  console_recovery_prompt
#   DESCRIPTION:  Presents an interactive recovery prompt on console when upgrade fails
#    PARAMETERS:  None
#       RETURNS:  0
#===============================================================================
console_recovery_prompt(){
    local backup_complete_f="/var/cache/elive-upgrader/full-os-backup/.backup-complete"
    local has_backup=0
    local choice=""
    local timeout_sec=60

    # Ensure stdin/stdout/stderr are redirected to active TTY/console for interactive keyboard input
    if [[ -e /dev/tty1 ]] && [[ -r /dev/tty1 && -w /dev/tty1 ]]; then
        exec < /dev/tty1 > /dev/tty1 2>&1
    elif [[ -e /dev/console ]] && [[ -r /dev/console && -w /dev/console ]]; then
        exec < /dev/console > /dev/console 2>&1
    elif [[ -e /dev/tty ]] && [[ -r /dev/tty && -w /dev/tty ]]; then
        exec < /dev/tty > /dev/tty 2>&1
    fi

    if [[ -f "${backup_complete_f}" ]]; then
        has_backup=1
    fi

    stty sane 2>/dev/null || true

    echo ""
    echo "======================================================================="
    echo "                      UPGRADE RECOVERY CONSOLE"
    echo "======================================================================="
    echo "The boot-time upgrade did not complete successfully."
    if ((has_backup)); then
        echo "A full OS backup is available at /var/cache/elive-upgrader/full-os-backup."
    fi
    echo ""
    echo "Please choose an action (or wait ${timeout_sec}s to continue standard boot):"
    if ((has_backup)); then
        echo "  1) Restore system from backup (Recommended)"
        echo "  2) Continue boot into current system"
        echo "  3) Open emergency root shell"
        echo "  4) Reboot system"
        echo "======================================================================="
        echo -n "Enter choice [1-4] (default: 2 in ${timeout_sec}s): "

        if read -t "${timeout_sec}" choice 2>/dev/null; then
            echo ""
        else
            echo ""
            echo "Timeout reached. Continuing standard boot..."
            choice="2"
        fi

        case "${choice}" in
            1)
                echo "Starting system restoration from backup..."
                if [[ -x "${SCRIPT_PATH}" ]]; then
                    if "${SCRIPT_PATH}" --restore-from-backup; then
                        sync
                        reboot -f || /sbin/reboot || reboot || true
                        exit 0
                    else
                        echo "Restoration failed. Returning to recovery prompt..."
                    fi
                else
                    echo "Error: Recovery script not found at ${SCRIPT_PATH}"
                fi
                ;;
            2|"")
                echo "Continuing with regular boot..."
                cleanup_and_disable
                ;;
            3)
                echo "Launching emergency shell. Type 'exit' when finished."
                stty sane 2>/dev/null || true
                bash --login || true
                ;;
            4)
                echo "Rebooting system..."
                sync
                reboot || /sbin/reboot || reboot -f || true
                exit 0
                ;;
            *)
                echo "Invalid choice. Continuing with regular boot..."
                cleanup_and_disable
                ;;
        esac
    else
        echo "  1) Continue boot into current system"
        echo "  2) Open emergency root shell"
        echo "  3) Reboot system"
        echo "======================================================================="
        echo -n "Enter choice [1-3] (default: 1 in ${timeout_sec}s): "

        if read -t "${timeout_sec}" choice 2>/dev/null; then
            echo ""
        else
            echo ""
            echo "Timeout reached. Continuing standard boot..."
            choice="1"
        fi

        case "${choice}" in
            1|"")
                echo "Continuing with regular boot..."
                cleanup_and_disable
                ;;
            2)
                echo "Launching emergency shell. Type 'exit' when finished."
                stty sane 2>/dev/null || true
                bash --login || true
                ;;
            3)
                echo "Rebooting system..."
                sync
                reboot || /sbin/reboot || reboot -f || true
                exit 0
                ;;
            *)
                echo "Invalid choice. Continuing with regular boot..."
                cleanup_and_disable
                ;;
        esac
    fi
    return 0
}

#===  FUNCTION  ================================================================
#          NAME:  cleanup_old_backups
#   DESCRIPTION:  Removes old OS backup directories from /root after completion
#    PARAMETERS:  None
#       RETURNS:  0
#===============================================================================
cleanup_old_backups(){
    local cleanup_flag_f="/var/cache/elive-upgrader/cleanup-backups-pending"

    if [[ ! -f "${cleanup_flag_f}" ]]; then
        return 0
    fi

    echo "Removing old /root/debian-upgrade-backup directories..."
    find /root -maxdepth 1 -type d -name 'debian-upgrade-backup-*' -exec rm -rf {} + 2>/dev/null || true
    find /root -maxdepth 1 -type f -name 'debian-upgrade-backup-*' -delete 2>/dev/null || true

    if [[ -d "/var/cache/elive-upgrader/full-os-backup" ]]; then
        echo "Removing full OS backup directory..."
        rm -rf "/var/cache/elive-upgrader/full-os-backup" 2>/dev/null || true
        echo "Full OS backup directory removed."
    fi

    rm -f "${cleanup_flag_f}"
    echo "Old backup directories cleaned up successfully."
    return 0
}

#===  FUNCTION  ================================================================
#          NAME:  validate_upgrade_state
#   DESCRIPTION:  Validates state file and configuration before proceeding with upgrade
#    PARAMETERS:  None
#       RETURNS:  0 if valid and should proceed, 1 if invalid or completed
#===============================================================================
validate_upgrade_state(){
    if [[ ! -r "${DEFAULTS_FILE}" ]]; then
        echo "State file not found or not readable: ${DEFAULTS_FILE}"
        cleanup_and_disable
        return 1
    fi

    . "${DEFAULTS_FILE}"

    if [[ "${UPGRADE_ENABLED}" != "yes" ]]; then
        echo "UPGRADE_ENABLED is not yes (value: \"${UPGRADE_ENABLED}\"), cleaning up state file"
        cleanup_and_disable
        return 1
    fi

    if [[ "${UPGRADE_COMPLETED}" == "yes" ]] && upgrade_check_target_reached "${TARGET_CODENAME}"; then
        echo "Target ${TARGET_CODENAME} already reached and completed. Running post-boot hooks and cleaning up."
        process_remove_if_not_before "${TARGET_CODENAME}"
        sed -i -e '/^interface-name=/d' "/tmp/system-connections/"* "/etc/NetworkManager/system-connections/"* 2>/dev/null || true
        cleanup_old_backups
        cleanup_and_disable
        return 1
    fi

    if [[ "${UPGRADE_IN_PROGRESS}" != "yes" ]]; then
        if [[ "${UPGRADE_COMPLETED}" == "yes" ]]; then
            echo "First boot of the new upgraded system detected. Running post-boot hooks..."
            process_remove_if_not_before "${TARGET_CODENAME}"
            cleanup_old_backups
        fi
        echo "UPGRADE_IN_PROGRESS is not yes (value: \"${UPGRADE_IN_PROGRESS}\"), cleaning up state file"
        cleanup_and_disable
        return 1
    fi

    if [[ -z "${TARGET_CODENAME}" ]]; then
        echo "TARGET_CODENAME is empty, cleaning up malformed state file"
        cleanup_and_disable
        return 1
    fi

    if [[ "${REBOOT_COUNT:-0}" -ge 5 ]] 2>/dev/null; then
        el_error "Too many reboots during upgrade (${REBOOT_COUNT:-0}). Aborting to prevent infinite loop."
        echo "Check logs at /var/log/elive-upgrader/ for details."
        cleanup_and_disable
        return 1
    fi

    rm -f "${LOCK_FILE}" 2>/dev/null || true

    return 0
}

#===  FUNCTION  ================================================================
#          NAME:  main
#   DESCRIPTION:  Main entry point for elive-boot-upgrader
#    PARAMETERS:  $@ = script arguments
#       RETURNS:  0 on success, exit_code on error
#===============================================================================
main(){
    local current_cn_v=""
    local exit_code_v=0
    local err_msg_v=""
    local latest_log_f=""

    echo "=== Elive Boot Upgrader ==="
    echo "Starting at $(date)"

    if ! validate_upgrade_state; then
        echo "Upgrade state validation: upgrade completed or not active. Restoring display and login services..."
        cleanup_and_disable
        exit 0
    fi

    suspend_tty1_and_dms

    . "${DEFAULTS_FILE}"

    current_cn_v="$(get_current_codename)"
    echo "Validated: upgrading from ${current_cn_v:-unknown} to ${TARGET_CODENAME}"

    if command -v plymouth &>/dev/null && plymouth --ping &>/dev/null; then
        plymouth quit 2>/dev/null || true
    fi

    if [[ ! -x "${SCRIPT_PATH}" ]]; then
        el_error "${SCRIPT_PATH} not found or not executable"
        cleanup_and_disable
        exit 1
    fi

    echo "Starting upgrade to ${TARGET_CODENAME}"
    export TERM="linux"
    set +e
    "${SCRIPT_PATH}" --boot-mode "${TARGET_CODENAME}"
    exit_code_v=$?
    set -e

    source /usr/lib/elive-tools/functions 2>/dev/null || true

    if [[ "${exit_code_v}" -ne 0 ]]; then
        if [[ "${exit_code_v}" -eq 143 ]] || [[ "${exit_code_v}" -eq 130 ]] || [[ -f /run/systemd/shutdown/scheduled ]] || [[ -f /run/systemd/shutdown ]]; then
            echo "Upgrade process was interrupted by system shutdown/reboot (exit code ${exit_code_v}). Preserving state for next boot."
            exit 0
        fi

        latest_log_f="$(ls -t /var/log/elive-upgrader/debian-upgrade-*.log 2>/dev/null | head -n 1 || true)"
        if [[ -n "${latest_log_f}" ]] && [[ -f "${latest_log_f}" ]]; then
            err_msg_v="$(tr -d '\r' < "${latest_log_f}" | grep -v -E '\(Reading database \.\.\.|^\s*Preparing to unpack\b' | grep -iE "E:|error:|insufficient space|failed|fail|cannot" 2>/dev/null | tail -n 5 || true)"
            if [[ -z "${err_msg_v}" ]]; then
                err_msg_v="$(tr -d '\r' < "${latest_log_f}" | grep -v -E '\(Reading database \.\.\.|^\s*Preparing to unpack\b' | tail -n 10 2>/dev/null || true)"
            fi
        fi

        if [[ -z "${err_msg_v}" ]]; then
            err_msg_v="Unknown error occurred during the boot upgrade process."
        fi

        el_error "Upgrade exited with code ${exit_code_v}. Last errors: ${err_msg_v}"
        echo "Check logs at /var/log/elive-upgrader/ for details"

        echo "Preserving upgrade state to resume on next boot (Reboot count: ${REBOOT_COUNT:-0}/5)"

        mkdir -p /var/log/elive-upgrader 2>/dev/null || true
        echo "${err_msg_v}" > /var/log/elive-upgrader/last-boot-upgrade-failure 2>/dev/null || true
        chmod 666 /var/log/elive-upgrader/last-boot-upgrade-failure 2>/dev/null || true

        if [[ -x "${SCRIPT_PATH}" ]]; then
            "${SCRIPT_PATH}" --setup-recovery-notification 2>/dev/null || true
        fi

        console_recovery_prompt

        cleanup_and_disable

        exit "${exit_code_v}"
    fi

    echo "Upgrade completed successfully at $(date)"

    # allow all interfaces (wifi device names can change)
    sed -i -e '/^interface-name=/d' "/tmp/system-connections/"* "/etc/NetworkManager/system-connections/"* 2>/dev/null || true

    cleanup_old_backups
    cleanup_and_disable

    echo "Rebooting system to apply changes in 10 seconds..."
    sync
    ( sleep 10 ; sync ; reboot || /sbin/reboot || reboot -f ) & disown 2>/dev/null || true
    exit 0
}

main "$@"
