#!/bin/bash

set -e

DB_HOST="localhost"
DB_PORT=5432
PGPASSWORD="proformatique"
DB_USERNAME="postgres"
DB_MIGRATION_VERSION="2025.06"
FACTORY_ENV_FILE="/etc/docker/xivo/factory.env"
CUSTOM_ENV_FILE="/etc/docker/xivo/custom.env"
PG_DATA_FOLDER="/var/lib/postgresql"
PG_17_DATA="$PG_DATA_FOLDER/17/data"
PG_15_DATA="$PG_DATA_FOLDER/15/data"
PG15_CONF_BACKUP_DIR="/var/tmp/xivo-migrate-db-15-to-17/postgresql-15-conf-backup/"

#shellcheck disable=SC1091
source /usr/bin/xivo-upgrade-functions

stop_services() {
    echo "Stopping services..."
    service cron stop
    pkill -f xivo-call-logs || true
}

start_services() {
    echo "Starting services..."
    service cron start
}

run_psql_file() {
  PGPASSWORD=${PGPASSWORD} psql -h $DB_HOST -p $DB_PORT -U $DB_USERNAME -t -f "$1"
}

is_postgres_running() {
    is_postgres_running_on_port "${PGPASSWORD}" "${DB_HOST}" "${DB_PORT}" "${DB_USERNAME}" "asterisk"
}

save_postgres15_conf() {
    local pg15_backup_dir="${1}"; shift

    mkdir -p "${pg15_backup_dir}"
    cp -aR "${PG_15_DATA}"/*.conf "${pg15_backup_dir}"
    cp -aR "${PG_15_DATA}"/conf.d/ "${pg15_backup_dir}"
}

wait_for_postgres() {
    local wait_time=120
    echo -e -n "Waiting $wait_time seconds for database db..."

    local db_running="false"
    for _ in $(seq 1 $wait_time); do
        if is_postgres_running; then
            db_running="true"
            break
        else
            sleep 1
            echo -e -n "."
        fi
    done
    echo
    if [ "$db_running" = "false" ]; then
        echo -e "\e[31mERROR: database is not running.\e[0m"
        exit 1
    fi
}

shutdown_database() {
    xivo-dcomp stop db
}

get_distribution() {
    local distribution=""
    if [ -f ${CUSTOM_ENV_FILE} ] && [ "$(grep -oP -m 1 'XIVOCC_DIST=\K.*' ${CUSTOM_ENV_FILE})" != "" ]; then
        distribution=$(grep -oP -m 1 'XIVOCC_DIST=\K.*' ${CUSTOM_ENV_FILE})
    else
        distribution=$(grep -oP -m 1 'XIVOCC_DIST=\K.*' ${FACTORY_ENV_FILE})
    fi
    echo -e "$distribution"
}

# Get locale of db
# Params:
#  - locale name
#  - db (default to template1)
#  - default locale (default to en_US.UTF-8)
# Returns locale or default locale if retrieved locale is null
get_locale() {
    local lc="${1}"; shift
    local pg_maintenance_db="${1:-"template1"}"; shift
    local default_lc="${1:-"en_US.UTF-8"}"; shift

    local res=""
    res=$(cd /tmp/ && sudo -u postgres psql -U postgres --quiet -tAc "SELECT DISTINCT ${lc} FROM pg_catalog.pg_database WHERE datname='${pg_maintenance_db}'")
    if [ -z "$res" ]; then
        # Set locale to en_US.UTF-8 if value is null
        res=${default_lc}
    fi
    echo "${res}"
}

get_tag() {
    local tag;
    tag=$(grep -oP -m 1 'XIVOCC_TAG=\K.*' ${FACTORY_ENV_FILE})
    echo "$tag"
}

migrate_15_to_17() {
    set -o pipefail
    local distribution="${1}"; shift
    local old_lc_collate="${1}"; shift
    local old_lc_ctype="${1}"; shift

    # Construct initdb args with encoding
    local postgres_initdb_args="--encoding UTF8 --lc-collate ${old_lc_collate} --lc-ctype ${old_lc_ctype}"

    echo -e "\e[33mPulling docker database container...\e[0m"
    local tag; tag=$(get_tag)
    docker pull "xivoxc/xivo-db:${tag}.${distribution}"

    echo -e  "\e[33mInit new postgres 17 database with locale ${old_lc_collate}, ${old_lc_ctype} ...\e[0m"
    docker run --rm \
        -e XIVO_EXIT_AFTER_INITDB="true" \
        -e POSTGRES_INITDB_ARGS="${postgres_initdb_args}" \
        -e POSTGRES_PASSWORD="proformatique" \
        -v /etc/timezone:/etc/timezone:ro \
        -v /etc/localtime:/etc/localtime:ro \
        -v /etc/passwd:/etc/passwd:ro \
        -v /etc/group:/etc/group:ro \
        -v /var/log/postgresql:/var/log/postgresql \
        -v /var/lib/postgresql/:/var/lib/postgresql/ \
        -v /run/postgresql:/run/postgresql \
        "xivoxc/xivo-db:${tag}.${distribution}" 2>&1
    
    #shellcheck disable=SC2181
    if [ $? -eq 0 ]; then 
        echo -e  "\e[32mPostgres 17 Init success with locale ${old_lc_collate}, ${old_lc_ctype} ...\e[0m"
    else
        echo -e  "\e[31mERROR: Postgres Init failed."
        exit 1;
    fi

    echo -e  "\e[33mStarting Migration container\e[0m"
    # Note: Using implicit parameter from tianon's image: PGDATANEW & PGDATAOLD
    docker run --rm \
        -v /etc/timezone:/etc/timezone:ro \
        -v /etc/localtime:/etc/localtime:ro \
        -v /var/lib/postgresql/:/var/lib/postgresql/ \
        "xivoxc/xivo-db-migration:${DB_MIGRATION_VERSION}.${distribution}" --link 2>&1
}

display_upgrade_end_notice() {
    echo -e "\e[32m*********************************************************************************"
    echo -e "*   XiVO Database was upgraded from Postgres version 15 to version 17        *"
    echo -e "*********************************************************************************\e[0m"
}

display_upgrade_start_notice() {
    echo -e "\e[32m*********************************************************************************"
    echo -e "*   About to upgrade Postgres from version 15 to version 17                  *"
    echo -e "*********************************************************************************\e[0m"
}


clean_pg_upgrade_remainders() {
    echo -e  "\e[33mRemove old cluster and clean pg_upgrade files\e[0m"
    rm -rf "${PG_DATA_FOLDER}/15" \
           "${PG_DATA_FOLDER}/data" \
            /var/lib/postgresql/delete_old_cluster.sh
}

add_access_configuration() {
    cp "${PG_15_DATA}/pg_hba.conf" "${PG_17_DATA}"
    cp -afu "${PG_15_DATA}"/conf.d/*.conf "${PG_17_DATA}/conf.d/"
}

pull_and_start_db() {
    xivo-dcomp upgrade-db
}

post_migration_steps() {
    if [ -f "/var/lib/postgresql/update_extensions.sql" ]; then
        run_psql_file "/var/lib/postgresql/update_extensions.sql"
    fi
}

migrate() {
    local distribution
    display_upgrade_start_notice
    echo -e "\e[32mStarting database migration to postgres 17...\e[0m"

    echo -e "\e[32mEnsure db is running...\e[0m"
    if ! is_postgres_running; then
        echo -e "\e[32mStarting the db...\e[0m"
        xivo-dcomp start db
        wait_for_postgres
    fi

    echo -e "\e[32mRetrieving the old database locale\e[0m"
    local old_lc_collate; old_lc_collate=$(get_locale "datcollate")
    local old_lc_ctype; old_lc_ctype=$(get_locale "datctype")

    echo -e "\e[32mStopping services that might be using the db...\e[0m"
    stop_services

    echo -e "\e[33mStopping db...\e[0m"
    shutdown_database
    if is_postgres_running; then
        echo -e "\e[31mERROR: Failed to stop database.\e[0m"
        exit 3
    fi

    echo "Saving postgres 15 conf to ${PG15_CONF_BACKUP_DIR}"
    save_postgres15_conf "${PG15_CONF_BACKUP_DIR}"

    echo -e "\e[33mPulling docker migration container...\e[0m"

    distribution=$(get_distribution)
    docker pull "xivoxc/xivo-db-migration:${DB_MIGRATION_VERSION}.${distribution}"


    echo -e "\e[33mRunning migration...\e[0m"
    if migrate_15_to_17 "$distribution" "$old_lc_collate" "$old_lc_ctype"; then
        echo -e "\e[32mDatabase upgrade successful.\e[0m"
        set +o pipefail

        echo -e "\e[33mRetrieve old conf (pg_hba.conf and conf.d) ...\e[0m"
        add_access_configuration

        echo -e "\e[33mCleaning old data ...\e[0m"
        clean_pg_upgrade_remainders

        echo -e "\e[33mStarting database container...\e[0m"
        pull_and_start_db
        wait_for_postgres

        post_migration_steps

        start_services

        display_upgrade_end_notice
    fi
}

if [ ! -d "$PG_17_DATA" ]; then
    migrate
else
    echo -e "\e[31mERROR: $PG_17_DATA directory exists.\e[0m"
fi

exit 0

