#!/bin/bash

set -e

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

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() {
    result=$(PGPASSWORD=${PGPASSWORD} psql -h "$DB_HOST" -p $DB_PORT -U $DB_USERNAME -qAtc "select 1 from pg_catalog.pg_database WHERE datname='postgres'" 2>/dev/null)

    [ $? -eq 0 ] && [ "$result" = "1" ]
}

save_postgres11_conf() {
    local pg11_backup_dir="${1}"; shift

    mkdir -p "${pg11_backup_dir}"
    cp -aR "${PG_11_DATA}"/*.conf "${pg11_backup_dir}"
    cp -aR "${PG_11_DATA}"/conf.d/ "${pg11_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}'")

    # Set locale to en_US.UTF-8 if value is null
    [ "x${res}" = "x" ] && res=${default_lc}
    echo ${res}
}

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

migrate_11_to_15() {
    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=$(get_tag)
    docker pull xivoxc/xivo-db:${tag}.${distribution}

    echo -e  "\e[33mInit new postgres 15 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

    if [ $? -eq 0 ]; then
        echo -e  "\e[32mPostgres 15 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 Dockerfile: PGDATANEW /var/lib/postgresql/15/data
    docker run --rm \
        -v /etc/timezone:/etc/timezone:ro \
        -v /etc/localtime:/etc/localtime:ro \
        -v /var/lib/postgresql/:/var/lib/postgresql/ \
        -e PGDATAOLD="$PG_11_DATA" \
        xivoxc/xivo-db-migration:${DB_MIGRATION_VERSION}."${distribution}" --link 2>&1
}

display_upgrade_notice() {
    echo -e "\e[32m*********************************************************************************"
    echo -e "*   XiVO Database was upgraded from Postgres version 11 to version 15        *"
    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}/11" \
           "${PG_DATA_FOLDER}/data" \
            /var/lib/postgresql/delete_old_cluster.sh
}

add_access_configuration() {
    cp "${PG_11_DATA}/pg_hba.conf" "${PG_15_DATA}"
    cp -afu "${PG_11_DATA}"/conf.d/*.conf "${PG_15_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
    echo -e "\e[32mStarting database migration to postgres 15...\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=$(get_locale "datcollate")
    local 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 11 conf to ${PG11_CONF_BACKUP_DIR}"
    save_postgres11_conf "${PG11_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"
    migrate_11_to_15 "$distribution" "$old_lc_collate" "$old_lc_ctype"

    if [ "$?" -eq 0 ]; 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_notice
    fi
}

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

exit 0

