#!/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/verbose.bash"

setlocale en_US.utf8 || :
# shellcheck disable=SC2034
declare -A op=()
declare -A ARGS=()

optparser-init op \
    --desc "Grant privileges to a role in the PostgreSQL database."
optparser-addopt op --name "privileges" --narg '+' \
    --add-choice ALL \
    --add-choice "ALTER SYSTEM" \
    --add-choice CONNECT \
    --add-choice CREATE \
    --add-choice DELETE \
    --add-choice EXECUTE \
    --add-choice INSERT \
    --add-choice MAINTAIN \
    --add-choice REFERENCES \
    --add-choice SELECT \
    --add-choice SET \
    --add-choice TEMP \
    --add-choice TEMPORARY \
    --add-choice TRIGGER \
    --add-choice TRUNCATE \
    --add-choice UPDATE \
    --add-choice USAGE \
    --help "privileges to be granted"
optparser-addopt op -l "--to-role" --narg 1 --required \
    --help "role (user) name"
optparser-addopt op -l "--on-table" --narg 1 \
    --help "table name"
optparser-addopt op -l "--on-all-tables-in-schema" --narg 1 \
    --help "schema name"
optparser-addopt op -l "--on-sequence" --narg 1 \
    --help "sequence name"
optparser-addopt op -l "--on-all-sequences-in-schema" --narg 1 \
    --help "schema name"
optparser-addopt op -l "--on-database" --narg 1 \
    --help "database name"
optparser-addopt op -l "--on-domain" --narg 1 \
    --help "domain name"
optparser-addopt op -l "--on-foreign-data-wrapper" --narg 1 \
    --help "fdw name"
optparser-addopt op -l "--on-foreign-server" --narg 1 \
    --help "server name"
optparser-addopt op -l "--on-function" --narg 1 \
    --help "routine name"
optparser-addopt op -l "--on-procedure" --narg 1 \
    --help "routine name"
optparser-addopt op -l "--on-routine" --narg 1 \
    --help "routine name"
optparser-addopt op -l "--on-all-functions-in-schema" --narg 1 \
    --help "schema name"
optparser-addopt op -l "--on-all-procedures-in-schema" --narg 1 \
    --help "schema name"
optparser-addopt op -l "--on-all-routines-in-schema" --narg 1 \
    --help "schema name"
optparser-addopt op -l "--on-language" --narg 1 \
    --help "lang name"
optparser-addopt op -l "--on-large-object" --narg 1 \
    --help "loid"
optparser-addopt op -l "--on-parameter" --narg 1 \
    --help "configuration parameter"
optparser-addopt op -l "--on-schema" --narg 1 \
    --help "schema name"
optparser-addopt op -l "--on-tablespace" --narg 1 \
    --help "tablespace name"
optparser-addopt op -l "--on-type" --narg 1 \
    --help "type name"
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; }
[[ ${ARGS[to-role]} =~ ^[a-z][a-z0-9_.-]{2,21}$ ]] || die "$0: invalid role name"

ON=
for key in "${!ARGS[@]}"; do
    [[ $key = on-* ]] || continue
    [[ -n $ON ]] && die "$0: multiple --on-* options"
    ON=$key
done
[[ -n $ON ]] || die "$0: one of the --on-* options is required"
[[ ${ARGS[$ON]} =~ ^[a-zA-Z0-9_.-]+$ ]] || die "$0: invalid $ON value"

[[ $EUID -eq 0 ]] || die "script should be run as root"

trap-init

eval "$("$SCRIPT_DIR/pgsql-pkginfo")"
[[ -n ${VCTL_PGSQL_PSQL:-} ]] || die "failed to find psql binary"

sql="GRANT"
if strarray-contains ALL "${ARGS[privileges]}"; then
    sql+=" ALL PRIVILEGES"
else
    sql+=" $(strarray-join "," "${ARGS[privileges]}")"
fi

case "$ON" in
    on-table)
        sql+=" ON TABLE \"${ARGS[$ON]}\""
    ;;
    on-all-tables-in-schema)
        sql+=" ON ALL TABLES IN SCHEMA \"${ARGS[$ON]}\""
    ;;
    on-sequence)
        sql+=" ON SEQUENCE \"${ARGS[$ON]}\""
    ;;
    on-all-sequences-in-schema)
        sql+=" ON ALL SEQUENCES IN SCHEMA \"${ARGS[$ON]}\""
    ;;
    on-database)
        sql+=" ON DATABASE \"${ARGS[$ON]}\""
    ;;
    on-domain)
        sql+=" ON DOMAIN \"${ARGS[$ON]}\""
    ;;
    on-foreign-data-wrapper)
        sql+=" ON FOREIGN DATA WRAPPER \"${ARGS[$ON]}\""
    ;;
    on-foreign-server)
        sql+=" ON FOREIGN SERVER \"${ARGS[$ON]}\""
    ;;
    on-function)
        sql+=" ON FUNCTION \"${ARGS[$ON]}\""
    ;;
    on-procedure)
        sql+=" ON PROCEDURE \"${ARGS[$ON]}\""
    ;;
    on-routine)
        sql+=" ON ROUTINE \"${ARGS[$ON]}\""
    ;;
    on-all-functions-in-schema)
        sql+=" ON ALL FUNCTIONS IN SCHEMA \"${ARGS[$ON]}\""
    ;;
    on-all-procedures-in-schema)
        sql+=" ON ALL PROCEDURES IN SCHEMA \"${ARGS[$ON]}\""
    ;;
    on-all-routines-in-schema)
        sql+=" ON ALL ROUTINES IN SCHEMA \"${ARGS[$ON]}\""
    ;;
    on-language)
        sql+=" ON LANGUAGE \"${ARGS[$ON]}\""
    ;;
    on-large-object)
        sql+=" ON LARGE OBJECT \"${ARGS[$ON]}\""
    ;;
    on-parameter)
        sql+=" ON PARAMETER \"${ARGS[$ON]}\""
    ;;
    on-schema)
        sql+=" ON SCHEMA \"${ARGS[$ON]}\""
    ;;
    on-tablespace)
        sql+=" ON TABLESPACE \"${ARGS[$ON]}\""
    ;;
    on-type)
        sql+=" ON TYPE \"${ARGS[$ON]}\""
    ;;
    *)
        die "$0: unsupported option: '--$ON'"
    ;;
esac

sql+=" TO \"${ARGS[to-role]}\";"

# shellcheck disable=SC2046
runuser -u postgres -- \
    "$VCTL_PGSQL_PSQL" -A -x -q -v ON_ERROR_STOP=1 $(verbose-arg -e) <<< "$sql"
