#!/bin/bash
SOURCE="$0"
source /usr/lib/elive-tools/functions
EL_REPORTS="1"
el_make_environment
if [[ -r "/etc/elive/settings" ]] ; then
    . "/etc/elive/settings"
fi
. gettext.sh
TEXTDOMAIN="elive-upgrader"
export TEXTDOMAIN

# Lock system (good one) {{{
lockfile="/tmp/.$(basename $0)-${USER}.lock"

exit_ok(){
    xhost -si:localuser:root >/dev/null 2>&1
    rm -f "$lockfile"
}
exit_error(){
    xhost -si:localuser:root >/dev/null 2>&1
    rm -f "$lockfile"
    exit 1
}

if [[ -r "$lockfile" ]] ; then
    PROCCESS="$(cat $lockfile)"
else
    PROCCESS=" "
fi
if (ps up $PROCCESS) 1>/dev/null 2>&1 ; then
    NOREPORTS=1 el_error "$(basename $0) already running"
    exit
else
    echo $$ > "$lockfile"
fi

# traps needs to be after the lock verification, in order to not remove it when we are already running
trap "exit_ok" EXIT
trap "exit_error" 1 2 3 5 6 14 ERR

# SET the lock file
echo "$$" > "$lockfile"


# end lock system }}}

show_help(){
    echo "Usage: $(basename "$0") [OPTIONS]"
    echo
    echo "Options:"
    echo "  -u, --upgrade    Force an immediate system upgrade"
    echo "  --delayed        Delay execution (used for background/autostart)"
    echo "  --betatest       Enable beta testing features"
    echo "  -h, --help       Show this help message"
    echo "  -f, --force      Force action"
}

main(){
    # pre {{{
    local pong was_anything_updated=0

    # allow root to access the user's display
    xhost +si:localuser:root >/dev/null 2>&1

    version_elive="$( cat "/etc/elive-version" | grep "elive-version:" | awk '{print $2}' )"
    read -r version_elive <<< "$version_elive"

    # distro version
    case "$( cat /etc/debian_version )" in
        13.*|"trixie"*)
            is_trixie=1
            hooks_d="/usr/lib/elive-upgrader/hooks-trixie"
            ;;
        12.*|"bookworm"*)
            is_bookworm=1
            hooks_d="/usr/lib/elive-upgrader/hooks-bookworm"
            ;;
        11.*|"bullseye"*)
            is_bullseye=1
            hooks_d="/usr/lib/elive-upgrader/hooks-bullseye"
            ;;
        10.*|"buster"*)
            is_buster=1
            hooks_d="/usr/lib/elive-upgrader/hooks-buster"
            ;;
        7.*|"wheezy"*)
            is_wheezy=1
            hooks_d="/usr/lib/elive-upgrader/hooks"
            ;;
        *)
            el_error "debian version unknown: $(cat /etc/debian_version)"
            el_error "TODO: new distro needs to be implemented correctly in all other tools, grep for is_bookworm to all source codes and update them"
            # fallback:
            hooks_d="/usr/lib/elive-upgrader/hooks"
            ;;
    esac

    # FIXME: confs in /etc
    #news_history="$HOME/.config/$(basename $0)/news-history.txt"
    #if ! [[ -e "$news_history" ]] ; then
        #mkdir -p "$( dirname "$news_history" )"
    #fi

    # }}}
    # never run... checks {{{
    el_config_get

    if grep -qsF "lockfs" /proc/cmdline ; then
        NOREPORTS=1 el_error "elive-upgrader is disabled in lockfs mode"
        exit
    fi
    # persistence upgrade {{{
    if grep -qsF "boot=live" /proc/cmdline ; then

        # we are in persistence?
        if grep -qs "persistence" /proc/cmdline && [[ -s /tmp/.persistence-space-free-at-boot ]] ; then
            if [[ "$( cat /tmp/.persistence-space-free-at-boot | grep "[[:digit:]]" | tail -1 )" -gt "1200000" ]] ; then

                if [[ -z "$conf_use_upgrader_in_live" ]] ; then
                    if $guitool --question --text="$( eval_gettext "Do you want automated updates? This will keep your Persistence updated with the latest packages and Elive features." )" 1>/dev/null 2>&1 ; then
                        conf_use_upgrader_in_live="yes"
                    else
                        conf_use_upgrader_in_live="no"
                    fi
                    el_config_save "conf_use_upgrader_in_live"
                else
                    if [[ "$conf_use_upgrader_in_live" = "no" ]] ; then
                        exit
                    fi
                fi
            else
                # not enough free space, dont use upgrader
                exit
            fi
        else
            # no persistence mode (only live mode), just exit
            el_info "Elive upgrader is disabled in normal Live mode, if you want to use your USB with Persistence"
            sleep 4
            exit
        fi
    fi
    # }}}

    # only run if first user
    #if ! grep -qs "^first-user: $USER\$" /etc/elive-version ; then
        #el_debug "This user is not the first one installed on the system, exiting..."
        #exit
    #fi

    # just a check to make sure that it work
    # The XAUTHORITY variable is temporarily set for `elive-upgrader-root`
    # to allow graphical applications to run securely via sudo.
    pong="$( timeout 10 sudo -n elive-upgrader-root --ping )"
    if [[ "$pong" != "pong" ]] ; then
        if grep -qs "^first-user: $USER\$" /etc/elive-version ; then
            el_error "user $USER has no 'sudo elive-upgrader-root --ping' privileges (without password)"
        fi
        exit 1
    fi

    # access to the graphical system from its parent user
    # Initialize sudo_args based on interactivity
    local sudo_args=()
    if ! ((is_interactive)) ; then
        sudo_args+=("-n")
    fi

    # Add DISPLAY and XAUTHORITY if they exist, making sure to quote them for safety
    if [[ -n "$DISPLAY" ]] ; then
        sudo_args+=("DISPLAY=$DISPLAY")
    fi
    if [[ -n "${XAUTHORITY:-}" ]] ; then
        sudo_args+=("XAUTHORITY=$XAUTHORITY")
    fi

    # TODO:
    #   - packages-list to install include with a diff or something
    # - E conf upgrader? (diff something?)
    #     - we can run the enlightenment-remote too
    # - what if new packages / packages to remove? what if startup applications to add?
    #   - parse a list of packages to add, then a list of packages to remove, and in the end ... (what if conflicts? like adding a package that has a file added that was in another package first), we should do that interactively so that the user can say Yes or No in the install of packages for security reasons? (but we should have it already tested)
    # - lock unable to shutdown while upgrading, or terminal stuff
    #   - add a flag in /tmp/ and a daemon to check for that file and wait if stills open (and add a message to show/tell about that)
    # XXX sometimes we want to simply upgrade the system, how we should deal with this? running apug in a cron or something? searching for packages from the elive repo in order to update them from a list (because the elive repo is the important one to update), hum...


    for arg in "$@"
    do
        case "$arg" in
            --delayed)
                is_delayed=1
                shift
                ;;
            --betatest)
                is_betatester=1
                is_force_upgrade=1
                touch /tmp/.elive-upgrader-betatest
                shift
                ;;
            -u|--upgrade)
                # Temporary placeholder, will be executed below with correct root_args
                ;;
            -f|--force)
                is_force_mode=1
                ;;
            #-s|--simulate)
                ## simulates the normal run / start from the daemon mode
                #export EL_DEBUG=3
                #export is_simulate=1
                #true
                #;;
            -h|--help)
                show_help
                exit 1
                ;;
        esac
    done

    # Arguments to pass to elive-upgrader-root (constructed after parsing arguments)
    local root_args=()
    if ((is_betatester)) ; then
        root_args+=("--betatest")
    fi

    # Handle immediate upgrade action if requested
    for arg in "$@"
    do
        case "$arg" in
            -u|--upgrade)
                sudo "${sudo_args[@]}" elive-upgrader-root "${root_args[@]}" --upgrade
                ;;
        esac
    done

    # }}}

    # Check for pending upgrade notifications / recovery state immediately BEFORE any delayed sleep
    if [[ -s "/var/log/elive-upgrader/last-boot-upgrade-failure" ]]; then
        local fail_msg
        fail_msg="$(cat /var/log/elive-upgrader/last-boot-upgrade-failure 2>/dev/null | colors-remove )"
        rm -f /var/log/elive-upgrader/last-boot-upgrade-failure 2>/dev/null || true
        true > /var/log/elive-upgrader/last-boot-upgrade-failure 2>/dev/null || true
        local user_msg
        user_msg="$(eval_gettext "The automatic boot-time system upgrade failed and was safely cancelled to prevent boot loops. Your system has been restored to its previous state.\n\nReason/Error:\n")"
        $guitool --error --text="${user_msg}${fail_msg}" 1>/dev/null 2>&1
    fi

    # Delegate pending notifications and recovery choices to recovery-notification if needed
    if [[ -s "/var/cache/elive-upgrader/notify-upgrade-failed-space" ]] || \
       [[ -s "/var/cache/elive-upgrader/notify-upgrade-complete" ]] || \
       [[ -s "/var/log/elive-upgrader/recovery-mode-pending" ]]; then
        if [[ ! -x "/usr/lib/elive-upgrader/recovery-notification" ]]; then
            sudo "${sudo_args[@]}" /usr/lib/elive-upgrader/debian-upgrader --setup-recovery-notification 2>/dev/null || true
        fi
        if [[ -x "/usr/lib/elive-upgrader/recovery-notification" ]]; then
            /usr/lib/elive-upgrader/recovery-notification || true
        fi
    fi

    # wait 30 seconds that the entire internet is set up and the timezones are correctly updated, we are not hurry
    if ((is_delayed)) ; then
        el_debug "delayed $(basename $0) 30 seconds"

        sleep 30

        # in the case we are shutding down computer just exit from the tool inmediately
        if pidof -cxq elive-pm ; then
            # if the elive-pm command is not simply the lock one:
            if ! ps xk comm o comm,args | grep -qs "^elive-pm.*elive-pm lock" ; then
                exit
            fi
        fi

        # wait 3 minutes but in the case we are shutding down computer just exit from the tool inmediately
        # for i in $(seq 180)
        # do
        #     if pidof -cxq elive-pm ; then
        #         # if the elive-pm command is not simply the lock one:
        #         if ! ps xk comm o comm,args | grep -qs "^elive-pm.*elive-pm lock" ; then
        #             exit
        #         fi
        #     fi
        #
        #     sleep 1
        # done
    fi

    # first, verify if we have internet
    if ! el_verify_internet ; then
        NOREPORTS=1 el_warning "no internet found, ignoring"
        exit 1
    fi

    # verify if we are metered
    if ! ((is_force_mode)) && el_verify_internet_metered ; then
        el_error "Your internet connection is metered. The Elive Upgrader will not run on metered connections to avoid unexpected data charges. Please connect to a non-metered network and try again. Or use the --force option if you really want to."
        exit
    fi

    # source functions
    source /usr/lib/elive-upgrader/functions.sh

    # fixes first (if)
    #el_debug "going to: previous fixes"
    #sudo $sudo_opts elive-upgrader-root --fix

    # update tool first (if)
    el_debug "going to: update-tool"
    sudo "${sudo_args[@]}" elive-upgrader-root "${root_args[@]}" --update-tool
    source /usr/lib/elive-upgrader/functions.sh

    # hooks: root
    el_debug "going to: hooks root pre"
    # XXX this is ugly, includes also the upgrading of packages
    if sudo "${sudo_args[@]}" elive-upgrader-root "${root_args[@]}" --hooks-root-pre ; then
        was_anything_updated=1
    fi

    # Check if a distro upgrade was scheduled during the pre-hooks
    if [[ -f "/etc/default/elive-distro-upgrade" ]] ; then
        local upgrade_enabled
        upgrade_enabled="$(grep "^UPGRADE_ENABLED=" /etc/default/elive-distro-upgrade 2>/dev/null | cut -d'"' -f2)"
        if [[ "$upgrade_enabled" = "yes" ]] ; then
            el_info "Distro upgrade has been scheduled. Exiting upgrader."
            exit 0
        fi
    fi

    # hooks: user
    el_debug "going to: hooks user pre"
    if run_hooks "user" "pre" ; then
        was_anything_updated=1
    fi


    # verify if enough time passed to check for upgrades and ask the user if upgrade the system
    el_debug "going to: upgrade full system (delayed, if enough time passed)"
    if ((is_force_upgrade)) ; then
        el_debug "beta test mode: checking for upgrades"
        if has_pending_distro_upgrade_hook ; then
            el_info "A new distro upgrade hook is available. Skipping regular system upgrade suggestion."
        else
            num_updates="$( sudo "${sudo_args[@]}" elive-upgrader-root "${root_args[@]}" --updates-available )"
            if [[ -n "$num_updates" ]] && [[ "$num_updates" -gt 0 ]] ; then
                if $guitool --question --text="${num_updates} $( eval_gettext "Updates available. Do you want to upgrade your system?" )" 1>/dev/null 2>&1 ; then
                    if sudo "${sudo_args[@]}" elive-upgrader-root "${root_args[@]}" --upgrade --noaptupdate ; then
                        was_anything_updated=1
                    fi
                fi
            fi
        fi
    else
        if upgrade_system_delayed ; then
            was_anything_updated=1
        fi
    fi


    # always update before to run (if the package has been updated we want to fetch new code too)
    source /usr/lib/elive-upgrader/functions.sh

    # hooks: root
    el_debug "going to: hooks root post"
    if sudo "${sudo_args[@]}" elive-upgrader-root "${root_args[@]}" --hooks-root-post ; then
        was_anything_updated=1
    fi

    # hooks: user
    el_debug "going to: hooks user post"
    if run_hooks "user" "post" ; then
        was_anything_updated=1
    fi

    if ((was_anything_updated)) ; then
        local is_distro_upgrade_scheduled=0
        if [[ -f "/etc/default/elive-distro-upgrade" ]] ; then
            local upgrade_enabled upgrade_completed
            upgrade_enabled="$(grep "^UPGRADE_ENABLED=" /etc/default/elive-distro-upgrade 2>/dev/null | cut -d'"' -f2)"
            upgrade_completed="$(grep "^UPGRADE_COMPLETED=" /etc/default/elive-distro-upgrade 2>/dev/null | cut -d'"' -f2)"
            if [[ "$upgrade_enabled" = "yes" ]] && [[ "$upgrade_completed" != "yes" ]] ; then
                is_distro_upgrade_scheduled=1
            fi
        fi

        if ((is_distro_upgrade_scheduled)) ; then
            el_info "Distro upgrade is scheduled or in progress. Suppressing system updated notification."
        else
            notify_user_system_updated
        fi
    else
        el_info "$( eval_gettext "Your system is up to date." )"
    fi

}

#
#  MAIN
#
main "$@"

# vim: set foldmethod=marker :


