#!/usr/bin/env bash

set -Eeuo pipefail
trap cleanup SIGINT SIGTERM ERR EXIT

script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P)
nevisadmin4_namespace=''
operator_namespace=''
run_options=( "all" "nevisadmin" "operator" "images" "crd" "permissions" "cert-manager" "nginx")
run_option="all"
container_registry=''
internal_registry=''
isRollback=false

usage() {
    cat <<EOF
Usage: $(basename "${BASH_SOURCE[0]}") [-r <run_option>] -n <nevis_namespace> -o <operator_namespace> [--rollback]

This script performs the Kubernetes upgrade. It can also roll back changes, to some extent.

Available options:

-h, --help                      Print this help and exit.
-r, --run-option                Set what you want to upgrade. options: [all, nevisadmin, operator, images, crd, permissions, cert-manager, nginx]. Note: "all" does not include "cert-manager" and "nginx". Default: all.
-n, --nevisadmin4-namespace     The namespace of NevisAdmin4. Must be set if --run-options is set to nevisdmin, or all.
-o, --operator-namespace        The namespace of NevisOperator. Must be set if --run-options is set to operator, or all.
-c, --container-registry        The container registry to upload the new images to. Also, the registry from where the images for Nevisadmin4 and NevisOperator are going to be pulled from. Must be set.
-i, --internal-registry By default, the registry url used by the pods is the same as the container-registry url. If you want the pods to use a different registry url, set it with this parameter.
--rollback                      With this flag, the operation(s) chosen in run-options will be rolled back to their previous state instead of being upgraded.

EOF
    exit
}

cleanup() {
    trap - SIGINT SIGTERM ERR EXIT
    # script cleanup here
}

parse_params() {
    if [ $# -eq 0 ]; then
      usage
      exit 0
    fi

    while :; do
        case "${1-}" in
        -h | --help) usage ;;
        --rollback) isRollback=true ;;
        -n | --nevisadmin4-namespace)
            nevisadmin4_namespace="${2-}"
            shift
            ;;
        -o | --operator-namespace)
            operator_namespace="${2-}"
            shift
            ;;
        -r | --run-option)
            run_option="${2-}"
            shift
            ;;
        -c | --container-registry)
            container_registry="${2-}"
            shift
            ;;
        -i | --internal-registry)
            internal_registry="${2-}"
            shift
            ;;
        -?*) ./lib/die.sh "Unknown option: $1" ;;
        *) break ;;
        esac
        shift
    done

    if [[ -z $container_registry ]] ; then
        ./lib/die.sh "The container-registry must be set"
    fi

    if [[ -z $internal_registry ]] ; then
        internal_registry="$container_registry"
    fi

    # shellcheck disable=SC2199
    # shellcheck disable=SC2076
    if [[ ! " ${run_options[@]} " =~ " ${run_option} " ]];
        then ./lib/die.sh "invalid run option ${run_option}. Allowed parameters are '${run_options[*]}', or omit setting this parameter, to upgrade everything"
    fi

    if [[ $run_option == "all" || $run_option == "nevisadmin" ]] ; then
        if [[ -z $nevisadmin4_namespace ]] ; then
            ./lib/die.sh "If NevisAdmin4 is to be upgraded, it's namespace must be set with -n or --nevisadmin4-namespace."
        fi
    fi

    if [[ $run_option == "all" || $run_option == "operator" ]] ; then
        if [[ -z $operator_namespace ]] ; then
            ./lib/die.sh "If NevisOperator is to be upgraded, it's namespace must be set with -o or --operator-namespace."
        fi
    fi

    return 0
}

setLibScriptsExecutable() {
    ./lib/msg.sh "Performing chmod +x on the upgrade scripts in the lib folder of this script to ensure that they can be run"

    if [[ ! -x lib/check-permissions.sh ]]
        then chmod +x lib/check-permissions.sh
    fi

    if [[ ! -x lib/nevisadmin-upgrade.sh ]]
        then chmod +x lib/nevisadmin-upgrade.sh
    fi

    if [[ ! -x lib/nevisadmin-database-upgrade.sh ]]
        then chmod +x lib/nevisadmin-database-upgrade.sh
    fi

    if [[ ! -x lib/operator-upgrade.sh ]]
        then chmod +x lib/operator-upgrade.sh
    fi

    if [[ ! -x lib/images-upgrade.sh ]]
        then chmod +x lib/images-upgrade.sh
    fi

    if [[ ! -x lib/crd-upgrade.sh ]]
        then chmod +x lib/crd-upgrade.sh
    fi

    if [[ ! -x lib/permission-upgrade.sh ]]
        then chmod +x lib/permission-upgrade.sh
    fi

    if [[ ! -x lib/cert-manager-upgrade.sh ]]
        then chmod +x lib/cert-manager-upgrade.sh
    fi

    if [[ ! -x lib/nginx-upgrade.sh ]]
        then chmod +x lib/nginx-upgrade.sh
    fi

    if [[ ! -x lib/msg.sh ]]
        then chmod +x lib/msg.sh
    fi

    if [[ ! -x lib/die.sh ]]
        then chmod +x lib/die.sh
    fi

    chmod +x lib/yq_linux_amd64
}

main() {
    setLibScriptsExecutable
    parse_params "$@"
    mkdir -p lib/tmp

    images_upgrade_parameters=( "-c" "$container_registry" )
    nevis_upgrade_parameters=( "-c" "$internal_registry" "-n" "$nevisadmin4_namespace" )
    operator_upgrade_parameters=( "-c" "$internal_registry" "-o" "$operator_namespace" )
    crd_upgrade_parameters=(  )
    permission_upgrade_parameters=(  )
    cert_manager_upgrade_parameters=(  )
    nginx_upgrade_parameters=(  )
    if [[ $isRollback = true ]] ; then
        images_upgrade_parameters+=( "--rollback" )
        nevis_upgrade_parameters+=( "--rollback" )
        operator_upgrade_parameters+=( "--rollback" )
        crd_upgrade_parameters+=( "--rollback" )
        permission_upgrade_parameters+=( "--rollback" )
        cert_manager_upgrade_parameters+=( "--rollback" )
        nginx_upgrade_parameters+=( "--rollback" )
    fi

    if [[ $run_option = "all" || $run_option = "images" ]] ; then
        ./lib/images-upgrade.sh "${images_upgrade_parameters[@]}"
    fi

    if [[ $run_option = "all" || $run_option = "nevisadmin" ]] ; then
        ./lib/nevisadmin-database-upgrade.sh "${nevis_upgrade_parameters[@]}"
    fi

    if [[ $run_option = "all" || $run_option = "nevisadmin" ]] ; then
        ./lib/nevisadmin-upgrade.sh "${nevis_upgrade_parameters[@]}"
    fi

    if [[ $run_option = "all" || $run_option = "operator" ]] ; then
        ./lib/operator-upgrade.sh "${operator_upgrade_parameters[@]}"
    fi

    if [[ $run_option = "all" || $run_option = "crd" ]] ; then
        # workaround, if the param array is empty and they are using a very old version of bash, it would otherwise pass
        # an "unassigned" variable instead of an empty array.
        # https://stackoverflow.com/questions/48394251/why-are-empty-arrays-treated-as-unset-in-bash/58261136#58261136
        ./lib/crd-upgrade.sh ${crd_upgrade_parameters[0]+"${crd_upgrade_parameters[@]}"}
    fi

    if [[ $run_option = "all" || $run_option = "permissions" ]] ; then
        ./lib/permission-upgrade.sh ${permission_upgrade_parameters[0]+"${permission_upgrade_parameters[@]}"}
    fi

    if [[ $run_option = "cert-manager" ]] ; then # "cert-manager" is excluded from "all"
        ./lib/cert-manager-upgrade.sh ${cert_manager_upgrade_parameters[0]+"${cert_manager_upgrade_parameters[@]}"}
    fi

    if [[ $run_option = "nginx" ]] ; then # "nginx" is excluded from "all"
        ./lib/nginx-upgrade.sh ${nginx_upgrade_parameters[0]+"${nginx_upgrade_parameters[@]}"}
    fi

    if [[ $run_option != "nginx" ]] ; then
        ./lib/msg.sh "WARNING: It is recommended to upgrade to the latest nginx version by rerunning this script with the 'nginx' run option.
        This requires kubernetes v1.20+.
        Only use the 'nginx' run option if nginx was installed with the manifest provided in the installation guide."
    fi

    if [[ $run_option != "cert-manager" ]] ; then
        ./lib/msg.sh "WARNING: Cert-manager can be used to generate certificates when using automatic key management. For more information,
        see the 'cert manager' section under 'Automatic Key Management' in the Nevis Configuration Guide. If this is used,
        the upgrade of the cert-manager to 1.4+ is required.
        This requires kubernetes v1.20+.
        If it was installed with the manifest provided in the installation guide, rerun this script with the 'cert-manager' run option."
    fi
}

main "$@"
