#!/bin/bash

# shellcheck source=../xivo-upgrade-functions
source /usr/bin/xivo-upgrade-functions
# shellcheck source=mds-upgrade-functions
source /usr/bin/mds-upgrade-functions

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

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

export_mds_version_to_env() {
    export MDS_VERSION_INSTALLED=$(get_mds_version_installed_from_apt)
    export MDS_VERSION_CANDIDATE=$(get_mds_version_candidate_from_apt)
}

display_mds_version() {
    local mds_version_candidate_colored
    mds_version_candidate_colored=$(color_diff_between_versions "$MDS_VERSION_INSTALLED" "$MDS_VERSION_CANDIDATE")
    echo ""
    echo "installed version : $MDS_VERSION_INSTALLED"
    echo -e "proposed update   : $mds_version_candidate_colored"
}

stop_mds() {
    xivo-service stop all
}

start_mds() {
    local rebuild_started="${1}"; shift

    xivo-dcomp up -d --remove-orphans
    wait_for_initial_copy "${rebuild_started}"
    xivo-service start
}

export_mds_cluster_locale() {
    MDS_CLUSTER_LOCALE=$(get_db_locale)
    export MDS_CLUSTER_LOCALE
}

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

mds_database_can_be_kept() {
    local image

    if ! is_subscription_streaming || ! is_initial_copy_done || ! is_main_slot_present; then
        echo "The replication from the XiVO Main is not running, not complete, or has no slot left on the XiVO Main."
        return 1
    fi

    image=$(get_candidate_db_image "${MDS_VERSION_CANDIDATE}")
    if [ -z "${image}" ]; then
        echo "Could not resolve the database image of the target version."
        return 1
    fi

    is_database_unchanged_by_image "${image}"
}

display_mds_database_decision() {
    local rebuild_db="${1}"; shift

    if [ "${rebuild_db}" -eq 1 ]; then
        cmn_echo_important "The database of this media server will be ERASED and rebuilt from the XiVO Main."
    else
        echo "The database of this media server is kept: its replication from the XiVO Main is intact."
    fi
}

abort_before_stopping() {
    display_upgrade_notice "Upgrade aborted: this media server was neither stopped nor upgraded."
    exit 1
}

check_upgrade_order_before_stopping() {
    local candidate_tag

    candidate_tag=$(get_xivocc_tag_of_version "${MDS_VERSION_CANDIDATE}")
    display_upgrade_notice "Pulling the database image of the target version..."
    if ! XIVOCC_TAG="${candidate_tag}" xivo-dcomp pull db; then
        abort_before_stopping
    fi

    display_upgrade_notice "Checking that the XiVO Main was upgraded first..."
    if ! check_upgrade_order "$(get_candidate_db_image "${MDS_VERSION_CANDIDATE}")"; then
        abort_before_stopping
    fi
}

install_mds_db_tools() {
    apt install --yes xivo-manage-db-mds
}

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

    add_xivo_apt_conf

    display_upgrade_notice "Executing pre-bookworm upgrade actions..."
    # Force install of new dahdi-linux-dkms module before switching to trixie
    # shellcheck disable=SC2086
    apt install --yes ${force_yes} -o Dpkg::Options::="--force-confnew" dahdi-linux-dkms

    # On MDS, force install of xivo-config before upgrade
    # shellcheck disable=SC2086
    apt install --yes ${force_yes} -o Dpkg::Options::="--force-confnew" xivo-config

    switch_to_trixie

    apt update

    display_upgrade_notice "Executing manual upgrade actions..."

    ## 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
    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 xivo-mds-installer to have new xivo-dcomp (which uses docker compose v2)
    # (Do not use --force-confnew to not force-rewrite factory.env file)
    # shellcheck disable=SC2086
    apt-get install --yes ${force_yes} xivo-mds-installer

    # re-stopping services after docker upgrade
    xivo-service stop
    ## End of docker specific part

    apt update

    display_upgrade_notice "Executing MDS 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 update
    apt autoremove --yes
}

mds_upgrade() {
    local rebuild_db="${1}"; shift
    local rebuild_started=""

    apt update

    export_mds_cluster_locale
    if [ "${rebuild_db}" -eq 1 ] && ! release_main_replication_slot_if_db_answers; then
        abort_before_stopping
    fi
    pre_stop "mds"
    stop_mds
    post_stop "mds"
    display_upgrade_notice "Upgrading mds..."
    if is_bookworm; then
        export XIVO_SYSTEM_UPGRADE=1
        exec_bookworm_to_trixie_migration
    else
        display_upgrade_notice "Upgrading media server..."
        display_upgrade_notice "Executing manual upgrade actions..."
        apt install --yes -o Dpkg::Options::="--force-confnew" xivo-config xivo-dist
        display_upgrade_notice "Executing full upgrade actions..."
        apt dist-upgrade --yes -o Dpkg::Options::="--force-confnew"
        display_upgrade_notice "Executing cleaning actions..."
        apt autoremove --yes
    fi

    install_mds_db_tools

    if [ "${rebuild_db}" -eq 1 ]; then
        rebuild_started=$(date +%s)
        rebuild_mds_db
    else
        upgrade_kept_mds_db
    fi

    pre_start "mds"
    start_mds "${rebuild_started}"
    post_start "mds"
    catch_up_initial_copy "${rebuild_started}"
    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
        	display_sources_list_notice
		else
		    display_system_upgrade_failure
		fi
    fi
}

upgrade_kept_mds_db() {
    xivo-dcomp upgrade-db
    wait_for_postgres
}

rebuild_mds_db() {
    mds-resync-db --no-service-control -f
    case $? in
        0) return 0;;
        "${RESYNC_FAILED_ERASED}") exit 1;;
        *)
            xivo-service stop all
            display_mds_database_recovery
            exit 1
        ;;
    esac
}

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

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


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

    if is_bookworm; then
        display_system_upgrade_notice
    fi
    display_mds_version

    if ! start_db_if_stopped "${force}" "${ignore_stats}"; then
        abort_before_stopping
    fi
    check_upgrade_order_before_stopping
    display_upgrade_notice "Checking whether the database of this media server can be kept..."
    if mds_database_can_be_kept; then
        rebuild_db=0
    fi
    display_mds_database_decision "${rebuild_db}"
    if ! check_mds_stats_replication "${force}" "${ignore_stats}" "${rebuild_db}"; then
        abort_before_stopping
    fi

    ask_to_continue_upgrade "${force}"
    local mds_upgrade_status_file="/tmp/mds-upgrade.status"
    recreate_upgrade_status_file_and_export "${mds_upgrade_status_file}"

    mds_upgrade "${rebuild_db}"
}

usage() {
    local progname="${1}"; shift

    echo "usage: ${progname} [-d] [-f] [-s] [-h]"
    echo -e "\t-d: only download packages"
    echo -e "\t-f: force install the proposed version"
    echo -e "\t-s: go on even if the statistics replication to the XiVO CC is stalled (the rows not sent yet are lost) or the database cannot be started"
    echo -e "\t-h: print usage"
}

main() {
    local progname="mds-upgrade"
    # Parse flags
    local download_only
    local force
    local ignore_stats
    while getopts :dfsh opt
    do
        case ${opt} in
            d) download_only=1;;
            f) force=1;;
            s) ignore_stats=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"}"
    ignore_stats="${ignore_stats:-"0"}"

    # Beginning
    export DEBIAN_FRONTEND=noninteractive
    export NEEDRESTART_MODE=l
    export APT_LISTCHANGES_FRONTEND=none

    export_mds_version_to_env

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

    if [ $download_only -eq 0 ]; then
        upgrading_system "${force}" "${ignore_stats}"
    else
        if is_bookworm; then
			check_enough_space_for_boot_partition "${force}"
            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 $MDS_VERSION_CANDIDATE | cut -d'.' -f1,2)
        xivo-dcomp pull --ignore-pull-failures
    fi
}

main "${@}"
