#!/bin/bash
# shellcheck disable=SC1091
#
# Copyright 2023 The qm Authors
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; If not, see <http://www.gnu.org/licenses/>.
#
# Capture the start time

START_TIME=$(date +%s)
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )

source "${SCRIPT_DIR}"/lib/utils
source "${SCRIPT_DIR}"/lib/container
source "${SCRIPT_DIR}"/lib/systemd
source "${SCRIPT_DIR}"/lib/tests

# GLOBALS
export CONFIG_NODE_AGENT_PATH="/etc/bluechi/agent.conf.d/agent.conf"
export REGISTRY_UBI8_MINIMAL="registry.access.redhat.com/ubi8/ubi-minimal"
export WAIT_BLUECHI_SERVER_BE_READY_IN_SEC=5
export CONTROL_CONTAINER_NAME="control"
export NODES_FOR_TESTING=("control" "node1")
export IP_CONTROL_MACHINE=""
export CONTAINER_CAP_ADD=""

export BUILD_QM_FROM_GH_URL=""
export BUILD_BLUECHI_FROM_GH_URL=""
export BRANCH_BLUECHI=""
export BRANCH_QM=""
export USE_QM_COPR="${PACKIT_COPR_PROJECT:-rhcontainerbot/qm}"

# If no additional nodes are required, use 1
if [ -z "${NUMBER_OF_NODES}" ]; then
    export NUMBER_OF_NODES=1
fi

if [ -z "${TAG_CONTROL_MACHINE}" ]; then
    export TAG_CONTROL_MACHINE="${CONTROL_CONTAINER_NAME}:latest"
fi

if [ -z "${NET_INTERFACE_IP_CONTROL}" ]; then
    export NET_INTERFACE_IP_CONTROL="eth0"
fi

if [ -t 1 ]; then
    RED='\033[91m'
    GRN='\033[92m'
    CLR='\033[0m'
fi

# ====================== Start - int main {} ;-)
ARGUMENT_LIST=(
    "build-qm-from-gh-url"
    "branch-qm"
    "use-qm-copr"
    "build-bluechi-from-gh-url"
    "branch-bluechi"
    "skip-tests"
    "number-of-nodes"
)

usage() {
cat <<EOF
Usage: ./run-test-e2e [OPTIONS]

--help
	This message

--build-qm-from-gh-url
	Build QM from a specific GitHub URL, useful for testing new features
--branch-qm
	Specify which branch the GitHub repo will be set. Requires --build-qm-from-gh-url
--use-qm-copr
        Specify to install rpms from rhcontainerbot/qm copr
--number-of-nodes
	Specify number of nodes. (default 1)

--build-bluechi-from-gh-url
	Build BLUECHI from a specific GitHub URL, useful for testing new features
--branch-bluechi
	Specify which branch the GitHub repo will be set. Requires --build-bluechi-from-gh-url
--skip-tests
	Specify to avoid testing. --skip-tests

Examples:

	No args, it will install latest qm and bluechi from copr rpm repository
		./run-test-e2e

	Build qm and bluechi from a specific github url and select the branches
		./run-test-e2e \\
			--branch-qm=superfeature \\
			--build-qm-from-gh-url=https://github.com/MYUSER/qm.git \\
			--branch-bluechi=superfeature \\
			--build-bluechi-from-gh-url=https://github.com/MYUSER/bluechi.git \\
			--use-qm-copr=Y \\

EOF
    exit 0
}

# read arguments
opts=$(getopt \
    --longoptions "$(printf "help,skip-systemctl,%s:," "${ARGUMENT_LIST[@]}")" \
    --name "$(basename "$0")" \
    --options "" \
    -- "$@"
)

eval set --"${opts}"

while [ $# -gt 0 ]; do
    case "$1" in
        --branch-qm)
            BRANCH_QM="${2}"
            shift 2
            ;;

        --branch-bluechi)
            BRANCH_BLUECHI="${2}"
            shift 2
            ;;

        --build-qm-from-gh-url)
            if [ -z "${BRANCH_QM}" ]; then
                BRANCH_QM="main"
            fi
            BUILD_QM_FROM_GH_URL="${2}"
            shift 2
            ;;

        --build-bluechi-from-gh-url)
            if [ -z "${BRANCH_BLUECHI}" ]; then
                BRANCH_BLUECHI="main"
            fi
            BUILD_BLUECHI_FROM_GH_URL="${2}"
            shift 2
            ;;

        --skip-tests)
            SKIP_TESTS="${2}"
            shift 2
            ;;

        --number-of-nodes)
            NUMBER_OF_NODES="${2}"

            # avoid "too many files opened"
            sysctl fs.inotify.max_user_instances=$((${2}*100)) 1> /dev/null

            shift 2
            ;;

        --use-qm-copr)
            USE_QM_COPR="${2}"
            shift 2
            ;;


        --help)
            usage
            ;;

        *)
            break
            ;;
    esac
done

info_message "Starting setup"
info_message "=============================="
if [ "$EUID" -ne 0 ]
then
    echo -e "[${RED} ERROR ${CLR}] Please run as root this script. It requires to set limits inside a container which is not allowed by root."
    exit
fi

cleanup

info_message "Creating dual stack network"
podman network \
    create --ipv6 --gateway fd00::1:8:1 --subnet fd00::1:8:0/112 \
    --gateway 10.90.0.1 --subnet 10.90.0.0/16 podmanDualStack

info_message "Cleaning any previous e2e files"

echo
info_message "Preparing ASIL environment"
info_message "=============================="

# If user would like to build bluechi from source code, let's adjust the ContainerFile
if [ -n "${BUILD_BLUECHI_FROM_GH_URL}" ]; then
    echo
    info_message "Building bluechi from source code, using:"
    info_message "=============================="
    info_message "\tGH URL: ${BUILD_BLUECHI_FROM_GH_URL}"
    info_message "\tBranch: ${BRANCH_BLUECHI}"
    echo
    sed -i -e 's#@BUILD_BLUECHI_FROM_GH_URL@#'"${BUILD_BLUECHI_FROM_GH_URL}"'#g' ./lib/ContainerFile.template
    sed -i -e 's/@BRANCH_BLUECHI@/'"${BRANCH_BLUECHI}"'/g' ./lib/ContainerFile.template
    sed -i -e 's/# \[manually install bluechi\] //' ./lib/ContainerFile.template
fi

# Creates the control container - a.k.a ASIL
create_asil_node

# Create pods regarding ASIL services
srvs_asil=("safety" "cruise_control" "tires" "breaks")
create_stub_systemd_srv "${CONTROL_CONTAINER_NAME}" "" "${srvs_asil[@]}"

echo
info_message "Preparing QM environment"
info_message "=============================="

# Creates the node container - a.k.a QM
create_qm_node

# Create pods regarding QM services
srvs_qm=("radio" "store" "stream_audio" "maps")

echo
for ((i=1;i<=NUMBER_OF_NODES;i++)); do
    create_stub_systemd_srv "node${i}" "qm" "${srvs_qm[@]}"
    echo
done

set_nodename_all_nodes
qm_set_nodename_all_nodes

# Tests
info_message "Starting tests"
info_message "=============================="
info_message "Waiting bluechi containers be ready..."
sleep "${WAIT_BLUECHI_SERVER_BE_READY_IN_SEC}"
# see: https://github.com/containers/bluechi/issues/281

if [ "${SKIP_TESTS}" == "yes" ]; then
    info_message "skip tests"
    info_message "=============================="
    exit 0
fi

echo
info_message "#1- Test scenario: bluechi list all units from control to node (vise-versa)"
test_bluechi_list_all_units

echo
info_message "${GRN}Summary of tests${CLR}"
info_message "=============================="
info_message "${GRN}ASIL environment${CLR}"
info_message "- 1 Controller container with:"
info_message "\t- bluechi service: manager and agent"
info_message "\t- ${#srvs_asil[@]} systemd generated and running:"
for srv in "${srvs_asil[@]}"; do
    info_message "\t\t container-${srv}"
done
echo

info_message "${GRN}QM environment${CLR}"
info_message "  Nodes:"
info_message "\t- ${NUMBER_OF_NODES} node(s) running as containers"
info_message "\t- bluechi service in each node: agent"
info_message "\t- 1 nested container running inside each node listed above"
echo
info_message "  QM Nodes (nested container):"
info_message "\t- ${NUMBER_OF_NODES} QM node(s) running inside in the nodes"
info_message "\t- bluechi service in each qm node: agent"
info_message "\t- ${#srvs_qm[@]} systemd generated and running in each QM node:"
for srv in "${srvs_qm[@]}"; do
    info_message "\t\t container-${srv}"
done
echo

info_message "${GRN}bluechictl calls${CLR}"
# 1 = controller node + NUMBER_OF_NODES * 2 (as we need to count the nested containers (qm))
info_message "\t- $((1+NUMBER_OF_NODES*2)) bluechictl calls to nodes"

# Capture the end time
END_TIME=$(date +%s)

# Calculate the duration in seconds
DURATION=$((END_TIME - START_TIME))

# Calculate minutes and seconds
DAYS=$((DURATION / 86400))
HOURS=$(( (DURATION % 86400) / 3600 ))
MINUTES=$(( (DURATION % 3600) / 60 ))
SECONDS=$((DURATION % 60))

echo
info_message "${GRN}Running time for this script${CLR}"
info_message "\t- ${DAYS} days, ${HOURS} hours, ${MINUTES} minutes and ${SECONDS} seconds"
echo
info_message "All set!"
echo
