#!/bin/bash

PATH=/bin:/usr/bin:/sbin:/usr/sbin
PG_17_DATA="/var/lib/postgresql/17"
LOG_XIVOCC_INSTALLER="/var/log/xivocc-installer.log"

source /usr/bin/xivo-upgrade-functions

execute() {
    cmd=$*
    $cmd
    if [ $? -ne 0 ]; then
        start_xivocc
        exit 1
    fi
}

stop_xivocc() {
    echo -e "\e[1;33mStopping XiVOCC containers...\e[0m"
    
    if output=$(xivocc-dcomp stop 2>&1 > /dev/null); then
        echo -e "\e[1;32mXiVOCC containers stopped successfully.\e[0m"
    else
        echo -e "\e[1;31mFailed to stop XiVOCC containers.\e[0m"
        echo -e "\e[1;31m$output\e[0m"
    fi
}

start_xivocc() {
    echo -e "\e[1;33mStarting XiVOCC containers...\e[0m"
    
    if output=$(xivocc-dcomp up -d --remove-orphans 2>&1 > /dev/null); then
        echo -e "\e[1;32mXiVOCC containers started successfully.\e[0m"
    else
        echo -e "\e[1;31mFailed to start XiVOCC containers.\e[0m"
        echo -e "\e[1;31m$output\e[0m"
    fi
}

export_xivocc_version_to_env() {
    export XIVOCC_VERSION_INSTALLED=$(get_xivocc_version_installed_from_apt)
    export XIVOCC_VERSION_CANDIDATE=$(get_xivocc_version_candidate_from_apt)
}

get_xivocc_version_installed_from_apt() {
    echo "$(LANG='C' apt-cache policy xivocc-installer | grep Installed | grep -oE '[0-9]{2,4}\.[0-9]+(\.[0-9]+)?|1\.2\.[0-9]{1,2}' | head -n1)"
}

get_xivocc_version_candidate_from_apt() {
    echo "$(LANG='C' apt-cache policy xivocc-installer | grep Candidate | grep -oE '[0-9]{2,4}\.[0-9]+(\.[0-9]+)?|1\.2\.[0-9]{1,2}' | head -n1)"
}

check_64bit_system() {
    machine=$(uname -m)
    if [ "$machine" = "i686" ]; then
		cat <<-EOF
		**********************************************************************
		* You are trying to upgrade to version that requires 64-bit system.  *
		* Upgrade aborted.                                                   *
		*                                                                    *
		* Please revert the sources list and downgrade the xivo-upgrade      *
		* package to the latest LTS version for 32-bit systems :             *
		* # xivo-dist xivo-polaris                                           *
		* # apt update                                                       *
		* # apt policy xivo-upgrade                                          *
		* # apt install xivo-upgrade=<AVAILABLE POLARIS VERSION>             *
		*                                                                    *
		**********************************************************************
		EOF
        exit 1
    fi
}

xivocc_upgrade() {
    apt update

    check_used_postgres "xivocc"
    pre_stop "xivocc"
    stop_xivocc
    post_stop "xivocc"
    display_upgrade_notice "Upgrading xivocc..."
    if is_bookworm; then
        export XIVO_SYSTEM_UPGRADE=1
        exec_bookworm_to_trixie_migration
    else
        display_upgrade_notice "Executing manual upgrade actions..."
        execute apt-get install -y -o Dpkg::Options::="--force-confnew" xivocc-installer

        display_upgrade_notice "Executing XiVOCC upgrade actions..."
        execute apt dist-upgrade -y -o Dpkg::Options::="--force-confnew"

        display_upgrade_notice "Executing cleaning actions..."
        apt autoremove -y
    fi
    if [[ "$USE_DB" == true ]]; then
        upgrade_db
    fi
    pre_start "xivocc"
    start_xivocc
    post_start "xivocc"
    display_upgrade_notice "Running post-upgrade actions..."
    if [[ "$XIVO_SYSTEM_UPGRADE" == "1" ]]; then
        check_if_grub_is_broken
        check_potential_interface_rename
		if is_trixie; then
        	display_system_upgrade_reboot_notice
		else
			display_system_upgrade_failure
		fi
    fi
    if [[ -f "$LOG_XIVOCC_INSTALLER" ]]; then
        display_xivocc_installer_log_notice
        cat "$LOG_XIVOCC_INSTALLER"
    fi
}

display_xivocc_version() {
    local xivocc_version_candidate_colored
    xivocc_version_candidate_colored=$(color_diff_between_versions "$XIVOCC_VERSION_INSTALLED" "$XIVOCC_VERSION_CANDIDATE")
    echo ""
    echo "installed version : $XIVOCC_VERSION_INSTALLED"
    echo -e "proposed update   : $xivocc_version_candidate_colored"
}

recreate_upgrade_status_file_and_export() {
    local status_file="${1}"; shift

    rm -f "${status_file}"
    touch "${status_file}"
    export XIVOCC_UPGRADE_STATUS_FILE=${status_file}
}

upgrading_system() {
    local force="${1}"; shift

    prepare_package_sources
    if is_bookworm; then
        check_enough_space_for_boot_partition
        display_system_upgrade_notice
    fi
    display_xivocc_version
    ask_to_continue_upgrade "${force}"
    local xivocc_upgrade_status_file="/tmp/xivo-upgrade.status"
    recreate_upgrade_status_file_and_export "${xivocc_upgrade_status_file}"

    xivocc_upgrade
}

upgrade_db() {
    if [ ! -d "$PG_17_DATA" ] ; then
        xivocc-upgrade-migrate-db-15-to-17

        if [ "$?" -ne 0 ]; then
            db_migration_error=1
        fi
    else
        xivocc-dcomp pull pgxivocc
        xivocc-dcomp up -d pgxivocc
        wait_for_postgres "xivocc" "localhost" "5443" "postgres" "xivo_stats"
    fi
}

exec_bookworm_to_trixie_migration() {
    local force_yes="--allow-downgrades --allow-remove-essential --allow-change-held-packages"

    display_upgrade_notice "Executing pre-trixie upgrade actions..."
    display_upgrade_notice ".. pre-trixie upgrade actions: switch repo to trixie"
    switch_to_trixie
    apt update

    display_upgrade_notice "Executing manual upgrade actions..."
    display_upgrade_notice ".. manual upgrade actions: upgrade docker"
    ## Docker specific part
    ## We want to control docker installation in order to not have uncontrolled container restart in the middle of the upgrade

    # Docker installation preparation
    install_xivo_docker
    # Docker package installs sources file according to /etc/os-release which is still bookworm at this stage
    # manually switch docker source list to target trixie repo
    sed -i 's/Suites: .*$/Suites: trixie/' /etc/apt/sources.list.d/docker.sources
    apt update

    # Upgrade docker-ce before xivo upgrade
    # shellcheck disable=SC2086
    apt install --yes ${force_yes} -o Dpkg::Options::="--force-confnew" docker-ce docker-ce-cli containerd.io

    # Install xivocc-installer to have new xivocc-dcomp
    # (Do not use --force-confnew to not force-rewrite factory.env file)
    # shellcheck disable=SC2086
    apt-get install --yes ${force_yes} xivocc-installer

    # re-stopping services after docker upgrade
    stop_xivocc
    ## End of docker specific part

    apt update

    display_upgrade_notice "Executing XiVOCC full upgrade actions..."
    # shellcheck disable=SC2086
    apt dist-upgrade --yes ${force_yes} -o Dpkg::Options::="--force-confnew"

    apt update
    display_upgrade_notice "Executing cleaning actions..."
    remove_deactivated_sources_list
    apt autoremove --yes
}

list_packages_with_filter() {
    local filter="$1"
    aptitude -q -F '%p' --disable-columns search "$filter"
}

prepare_package_sources () {
    install_xivo_dist
}

install_xivo_docker() {
    apt install --yes xivo-docker
}

install_xivo_dist() {
    is_dist_installed=$(list_packages_with_filter "?installed?name(\"^xivo-dist$\")")
    if [ -z "$is_dist_installed" ]; then
        echo "Installing xivo-dist package..."
        if ! apt install --yes xivo-dist; then
            echo "Failed to install xivo-dist. Aborting upgrade."
            exit 1
        fi
    fi
}

main() {
    local progname="xivocc-upgrade"
    # Parse flags
    local download_only
    local force
    while getopts :dfh opt
    do
        case ${opt} in
            d) download_only=1;;
            f) force=1;;
            h)
                usage "${progname}"
                exit 0
            ;;
            '?')
                echo "${progname} : option ${OPTARG} is not valid" >&2
                usage "${progname}"
                exit 1
            ;;
        esac
    done
    download_only="${download_only:-"0"}"
    force="${force:-"0"}"

    # Beginning
    export DEBIAN_FRONTEND=noninteractive
    export APT_LISTCHANGES_FRONTEND=none

    check_64bit_system
    export_xivocc_version_to_env
    if (! is_bookworm && ! is_trixie); then
        echo "Upgrade aborted."
        echo "Your XiVOCC is lower than Maia (2024.05) and uses Debian 11 or lower"
        echo "Upgrade to XiVOCC >= 2026.05 (which uses Debian 13) is not supported"
        echo "You MUST first upgrade to a XiVOCC >= Maia (2024.05)"
        exit 1
    fi

    if [ $download_only -eq 0 ]; then
        upgrading_system "${force}"
    else
        trap : SIGINT
        if is_bookworm; then
            check_enough_space_for_boot_partition

            # Switch repo to trixie
            switch_to_trixie
            apt update

            # Download packages
            apt -y -d -o Dpkg::Options::="--force-confnew" dist-upgrade

            # Rollback
            rollback_apt_sources_list
            apt update
        else
            # Download packages
            apt -y -d -o Dpkg::Options::="--force-confnew" dist-upgrade
        fi
        # Pull container
        export XIVOCC_TAG=$(echo $XIVOCC_VERSION_CANDIDATE | cut -d'.' -f1,2)
        xivocc-dcomp pull --ignore-pull-failures
    fi
}

main "${@}"
