#!/bin/bash

# Copyright (c) Veeam Software Group GmbH

set -eE -u -o pipefail

SCRIPT_DIR=$(dirname "$(realpath "${BASH_SOURCE[0]}")"); readonly SCRIPT_DIR;
source "$SCRIPT_DIR/lib/error-handle.bash"
source "$SCRIPT_DIR/lib/optparser.bash"
source "$SCRIPT_DIR/lib/str.bash"
source "$SCRIPT_DIR/lib/verbose.bash"

readonly PGSQL_EXTRA=(
    contrib
    plperl
)
readonly PKG_EXTRA=(
    perl-Digest-Perl-MD5
    consul
    patroni-consul
    python3-click
)

# shellcheck disable=SC2034
declare -A op=()
declare -A ARGS=()

setlocale en_US.utf8 || :
optparser-init op \
    --desc "Install the PostgreSQL database and its additional components."
optparser-addopt op --name "version" --narg 1 \
    --help "version to be installed"
optparser-addopt op -s "-f" -l "--force" \
    --help "force install additional missing components if a compatible version is already installed"
optparser-addopt op -s "-v" -l "--verbose" \
    --help "provide more detailed output"
optparser-addopt op -s "-h" -l "--help" \
    --help "show this help message and exit"
optparser-ignore-required op help
optparser-parse op ARGS "$@" || exit 1
[[ -n ${ARGS[help]:-} ]] && { optparser-help op; exit 0; }
[[ -n ${ARGS[verbose]:-} ]] && { verbose-enable; }

[[ $EUID -eq 0 ]] || die "script should be run as root"
declare -A os_release
parse-os-release os_release
case "${os_release[ID]}" in
    rocky | rhel) ;;
    *) die "unsupported OS \"${os_release[PRETTY_NAME]}\"" ;;
esac

trap-init

pkgname=; pkgversion=; pkgrepo=
lspkg() {
    local -a output=()
    str-split output "$("$SCRIPT_DIR/pgsql-lspkg" -t -L "$@" | tail -1)" $'\t'
    if (( ${#output[@]} >= 2 )); then
        pkgname=${output[0]}
        pkgversion=${output[1]}
        pkgrepo=${output[2]:-}
        return 0
    else
        pkgname=; pkgversion=; pkgrepo=
        return 1
    fi
}

extrapkg() {
    local basename=${pkgname/-server/}
    printf "${basename//%/%%}-%s-${pkgversion//%/%%}\n" "${PGSQL_EXTRA[@]}"
    printf "%s\n" "${PKG_EXTRA[@]}"
}

if lspkg -i "${ARGS[version]}"; then

    # Installed version with compatible version
    msg="found installed $pkgname version $pkgversion ${pkgrepo:+from repository $pkgrepo}"
    if [[ -n ${ARGS[force]:-} ]]; then
        verbose-echo "${msg@u}"
        # shellcheck disable=SC2046
        extrapkg | xargs -r dnf $(non-verbose-arg -q) -y install
    else
        die "$msg" "To install additional components please provide --force option"
    fi

elif lspkg -i; then

    # Installed version with compatible version
    die "found installed $pkgname with incompatible version $pkgversion ${pkgrepo:+from repository $pkgrepo}"

elif lspkg "${ARGS[version]}"; then

    module=$({
        dnf -qy module provides "$pkgname-$pkgversion" \
            | sed -ne 's/^Module\s*:\s*\(.\+\)/\1/p' \
            | tail -1
    })
    mapfile -t module_all < \
        <(dnf -qy module provides "postgresql-server" | sed -ne 's/^Module\s*:\s*\(.\+\)/\1/p')
    mapfile -t module_pkg < \
        <(dnf -qy module repoquery --installed "${module_all[@]}")

    verbose-echo "Will install $pkgname version $pkgversion" \
        "${module:+from module $module}" \
        "${pkgrepo:+from repository $pkgrepo}"

    if [[ -n "$module" ]]; then
        if [[ -n "${module_pkg[*]}" ]]; then
            # shellcheck disable=SC2046
            dnf $(non-verbose-arg -q) -y module enable "$module" \
                || die "cannot enable module $module due to installed packages:" \
                    "${module_pkg[@]}"
        else
            # shellcheck disable=SC2046
            dnf $(non-verbose-arg -q) -y module switch-to "$module"
        fi
    elif [[ -n "${module_pkg[*]}" ]]; then
        die "cannot install $pkgname due to installed next packages from module:" \
            "${module_pkg[@]}"
    else
        # shellcheck disable=SC2046
        dnf $(non-verbose-arg -q) -y module disable "${module_all[@]%%:*}"
    fi

    # shellcheck disable=SC2046
    extrapkg | xargs dnf $(non-verbose-arg -q) -y install "$pkgname-$pkgversion"

else
    die "cannot find PostgreSQL with a compatible version"
fi
