#!/bin/bash
# Copyright 2011-2025 The Wazo Authors  (see the AUTHORS file)
# SPDX-License-Identifier: GPL-3.0-or-later

PATH=/bin:/usr/bin:/sbin:/usr/sbin
lib_directory="/usr/share/wazo-upgrade"
: ${WAZO_CONFD_PORT:='9486'}

APT_OPTIONS='-o DPkg::Lock::Timeout=15'

# force all debian upgrade to non interactive mode
export DEBIAN_FRONTEND=noninteractive
export APT_LISTCHANGES_FRONTEND=none

fatal_error() {
	message=$1
	echo "******************* ERROR *************************"
	echo "An error occurred during the upgrade."
	echo "Please check /var/log/wazo-upgrade.log for details."
	[ -n "$message" ] && echo -e "Error: $message"
	echo "******************* ERROR *************************"
	exit -1
}

is_package_installed() {
	[ "$(dpkg-query -W -f '${Status}' "$1" 2>/dev/null)" = 'install ok installed' ]
}

differed_action() {
	local state=$1
	shopt -qs nullglob  # avoid failing when action directory has no scripts
	for script in "$lib_directory/$state.d"/*; do
		echo "Executing upgrade script $script..."
		$script
	done
	shopt -qu nullglob
}

pre_stop() {
	shopt -qs nullglob  # avoid failing when pre-stop directory has no scripts
	for script in "$lib_directory/pre-stop.d"/*; do
		echo "Executing upgrade script $script..."
		$script
		if [ $? -ne 0 ]; then
			fatal_error "Failed to execute $script\nPlease, fix this issue before re-executing wazo-upgrade"
		fi
	done
	shopt -qu nullglob
}

post_stop() {
	differed_action post-stop
}

pre_start() {
	differed_action pre-start
}

post_start() {
	differed_action post-start
}

execute() {
	cmd=$*
	if [ $? -ne 0 ]; then
		start_wazo
		fatal_error
	fi
	$cmd
	if [ $? -ne 0 ]; then
		start_wazo
		fatal_error
	fi
}

stop_wazo() {
	wazo-service stop
	wazo-service disable
}

start_wazo() {
	wazo-service enable
	wazo-service restart
}

upgrade() {
	export WAZO_VERSION_INSTALLED=$(wazo_version_installed)
	export WAZO_VERSION_CANDIDATE=$(wazo_version_candidate)
	export XIVO_VERSION_INSTALLED=$WAZO_VERSION_INSTALLED
	export XIVO_VERSION_CANDIDATE=$WAZO_VERSION_CANDIDATE
	pre_stop
	stop_wazo
	post_stop
	echo "Upgrading wazo..."
	execute apt-get install $APT_OPTIONS -o Dpkg::Options::="--force-confnew" -y postgresql-15
	execute apt-get install $APT_OPTIONS -o Dpkg::Options::="--force-confnew" -y wazo-platform
	execute apt-get install $APT_OPTIONS -o Dpkg::Options::="--force-confnew" -y xivo-config
	execute apt-get install $APT_OPTIONS -o Dpkg::Options::="--force-confnew" -y rabbitmq-server
	execute apt-mark auto $APT_OPTIONS postgresql-15 xivo-config rabbitmq-server
	execute apt-get dist-upgrade $APT_OPTIONS -y
	execute apt-get autoremove $APT_OPTIONS -y
	pre_start
	start_wazo
	post_start
	wazo-check-conffiles
}

display_wazo_version() {
	echo "installed version : $(wazo_version_installed)"
	echo "proposed update	: $(wazo_version_candidate)"
}

debian_version_installed() {
	cut -d. -f1 /etc/debian_version
}

upgrading_system() {
	display_wazo_version
	display_asterisk_notice
	if [ $force -eq 0 ]; then
		read -p 'Would you like to upgrade your system (all services will be restarted) [Y/n]? ' answer
		answer="${answer:-Y}"
		if [ "$answer" != 'y' -a "$answer" != 'Y' ]; then
			exit
		fi
	fi
	upgrade
}

display_asterisk_notice() {
	ast_version=$(dpkg-query -W -f '${Version}' asterisk 2>/dev/null)
	case "$ast_version" in
		8:19.*)
			ast_major_version="19"
			;;
		*)
			ast_major_version="unknown"
			;;
	esac
	if dpkg --compare-versions "$ast_version" le 8:20; then
		cat <<-EOF

		Asterisk will be upgraded from version $ast_major_version to 20. You might be impacted if you have:

		* custom Asterisk configuration (other than custom dialplan)
		* custom application using AMI or ARI
		* custom Asterisk modules (e.g. codec_g729a.so)

		If you find yourself in one of these cases, you should make sure that
		your customizations still work with Asterisk 20. Please refer to the
		Wazo upgrade notes for more information.

		EOF

		custom_modules=$(wazo-asterisk-custom-modules)
		if [ -n "$custom_modules" ]; then
			for module in $custom_modules; do
				mv "/usr/lib/asterisk/modules/$module" /tmp
			done
			cat <<-EOF
			WARNING: custom Asterisk modules detected:

			$custom_modules

			Since these modules will not work with Asterisk 20 and might cause major
			instability issues, they have been moved from /usr/lib/asterisk/modules to
			/tmp. To continue using these modules, you will have to install (or recompile)
			the Asterisk 20 version of these modules.

		EOF
		fi
	fi
}

wazo_version_installed() {
	echo "$(LANG='C' apt-cache policy $APT_OPTIONS wazo-platform | grep Installed | grep -oE '[0-9]{2}\.[0-9]+(\.[0-9]+)?' | head -n1)"
}

wazo_version_candidate() {
	echo "$(LANG='C' apt-cache policy $APT_OPTIONS wazo-platform | grep Candidate | grep -oE '[0-9]{2}\.[0-9]+(\.[0-9]+)?' | head -n1)"
}

check_wizard_has_been_run() {

	if ! is_wazo_configured; then
  		echo "ERROR: You must configure Wazo by running the wizard (POST /api/confd/1.1/wizard) before using wazo-upgrade"
		exit 1
	fi
}

is_wazo_configured() {
    if ! systemctl is-active --quiet wazo-confd; then
		echo "ERROR: wazo-confd is not running: cannot check if the wizard has been run."
		exit 1
	fi
	# wazo-confd has no HTTPS since wazo-20.07
	for scheme in 'http' 'https'; do
		if [ -n "$(curl -skX GET --header 'Accept: application/json' "$scheme://localhost:$WAZO_CONFD_PORT/1.1/wizard" | grep '\"configured\"[[:space:]]*:[[:space:]]*true')" ]; then
			return
		fi
	done
	return 1
}

usage() {
	cat <<-EOF
	usage: wazo-upgrade [-d] [-f] [-h]
		-d: only download packages
		-f: force yes
		-h: print usage
	EOF
}

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

check_wizard_has_been_run

if [ $download_only -eq 0 ]; then
	upgrading_system
else
	apt-get -y -d dist-upgrade $APT_OPTIONS
fi
