#!/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 "Control Veeam Backup services."
optparser-addopt op --name "cmd" --narg 1 \
    --add-choice "list" \
    --add-choice "status" \
    --add-choice "start" \
    --add-choice "stop" \
    --add-choice "restart" \
    --add-choice "enable" \
    --add-choice "disable" \
    --help "command to interact with services"
optparser-addopt op -s "-t" -l "--timeout" --narg 1 \
    --default 15m \
    --help "timeout for starting services;" \
    --help "floating point number with an optional suffix: s (seconds), m (minutes), h (hours), d (days)"
optparser-addopt op -s "-L" -l "--no-legend" \
    --help "disable the column headers"
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; }

trap-init

coproc lssvc {
    {
        "$SCRIPT_DIR/vctl-setup-tool" servicesprovider
        printf "%s\n" "veeam-platform-service-ahv.service" \
                      "veeam-platform-service-aws.service" \
                      "veeam-platform-service-gcp.service" \
                      "veeam-platform-service-kasten.service" \
                      "veeam-platform-service-pve.service" \
                      "veeam-platform-service-azure.service" \
                      "veeam-platform-service-scp.service"
    } \
        | awk 'NF && !x[$0]++' \
        | grep -v "veeamidentitysvc.service" \
        | grep -v "veeamidentityemsvc.service" \
        | grep -v "veeamhasvc.service" \
        | xargs -r systemctl list-unit-files --no-legend \
        | awk '{print $1}' \
        | sort
}
lssvc_pid=$!
mapfile -t VCTL_SERVICES <&"${lssvc[0]}"
wait $lssvc_pid || die "failed to get services list"
unset lssvc_pid lssvc
readonly VCTL_SERVICES

svcstatus() {
    local i; for ((i=0; i<$#; i++)); do [[ ${!i} = "--" ]] && break; done
    [[ ${!i:-} = "--" ]] || (( i = $# + 1 ))
    local -a services=("${@:1:i-1}")
    local -a awkcmd=(awk 
        -v nolegend="${ARGS[no-legend]:-0}"
        -v verbose="${VCTL_VERBOSE:-0}"
        -f "$SCRIPT_DIR/lib/svcstatus.awk"
        "${@:i+1}"
    )
    if (( ${#services[@]} > 0 )); then
        systemctl show --value -p Id,LoadState,ActiveState,SubState "${services[@]}" \
            | "${awkcmd[@]}"
    else
        "${awkcmd[@]}" < /dev/null
    fi
}

case "${ARGS[cmd]}" in
    list)
        printf "%s\n" "${VCTL_SERVICES[@]}"
    ;;
    status)
        trap-reset
        svcstatus "${VCTL_SERVICES[@]}" -- -e '
            BEGIN { if (!nolegend) pheader() }
            { pstatus() }
            verbose { psvclog() }
            END { exit nactive == NR ? 0 : 3 }
        '
    ;;
    start)
        verbose-cmd timeout "${ARGS[timeout]}" systemctl start "${VCTL_SERVICES[@]}" &
        svcstatus -- -e 'BEGIN { if (!nolegend) pheader() }'
        exec {stdout}>&1
        services=("${VCTL_SERVICES[@]}")
        while jobs -l %% >/dev/null 2>&1; do
            mapfile -t services < <({
                svcstatus "${services[@]}" -- \
                    -v stdout=$stdout \
                    -e '
                        is_active   { pstatus(stdout); if (verbose) psvclog(stdout); }
                        ! is_active { print service }
                    '
            })
            sleep 0.25
        done
        trap-reset
        svcstatus "${services[@]}" -- -e '
            { pstatus(); if (verbose) psvclog(); }
            ! is_active { print service > fdfile(2); psvclog(2, 20); }
            END { exit nactive == NR ? 0 : 3 }
        '
    ;;
    stop)
        verbose-cmd timeout "${ARGS[timeout]}" systemctl stop "${VCTL_SERVICES[@]}" &
        svcstatus -- -e 'BEGIN { if (!nolegend) pheader() }'
        exec {stdout}>&1
        services=("${VCTL_SERVICES[@]}")
        while jobs -l %% >/dev/null 2>&1; do
            mapfile -t services < <({
                svcstatus "${services[@]}" -- \
                    -v stdout=$stdout \
                    -e '
                        is_stopped   { pstatus(stdout); if (verbose) psvclog(stdout); }
                        ! is_stopped { print service }
                    '
            })
            sleep 0.25
        done
        trap-reset
        svcstatus "${services[@]}" -- -e '
            { pstatus(); if (verbose) psvclog(); }
            ! is_stoped { print service > fdfile(2); psvclog(2, 20); }
            END { exit nstopped == NR ? 0 : 3 }
        '
    ;;
    restart)
        a=(--timeout "${ARGS[timeout]}")
        [[ -n ${ARGS[verbose]:-} ]] && a+=("--verbose")
        [[ -n ${ARGS[no-legend]:-} ]] && a+=("--no-legend")
        "$0" "${a[@]}" stop
        "$0" "${a[@]}" --no-legend start
    ;;
    enable)
        # shellcheck disable=SC2046
        verbose-cmd systemctl $(non-verbose-arg -q) enable "${VCTL_SERVICES[@]}"
    ;;
    disable)
        # shellcheck disable=SC2046
        verbose-cmd systemctl $(non-verbose-arg -q) disable "${VCTL_SERVICES[@]}"
    ;;
esac
