#!/usr/bin/env bash

set -Eeuo pipefail

nevisadmin4_namespace=''
image_prefix=''
image_version=''
container_registry=''
isRollback=false

parseParams() {
    while :; do
        case "${1-}" in
        --rollback) isRollback=true ;;
        -n | --nevisadmin4-namespace)
            nevisadmin4_namespace="${2-}"
            shift
            ;;
        -c | --container-registry)
            container_registry="${2-}"
            shift
            ;;
        -?*) ./lib/die.sh "Unknown option: $1" ;;
        *) break ;;
        esac
        shift
    done

    [[ -z "${nevisadmin4_namespace-}" ]] && ./lib/die.sh "Missing required parameter: nevisadmin4-namespace"

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

    image_version=$(lib/yq_linux_amd64 'e' '.versions.nevisadmin4' 'lib/config.yaml')
    image_prefix=$(lib/yq_linux_amd64 'e' '.image-prefix' 'lib/config.yaml')
}

runChecks() {
    ./lib/msg.sh "Checking permissions..."
    ./lib/check-permissions.sh "patch statefulset" "$nevisadmin4_namespace"
    ./lib/check-permissions.sh "get statefulset" "$nevisadmin4_namespace"
    ./lib/check-permissions.sh "get secret" "$nevisadmin4_namespace"
    ./lib/check-permissions.sh "create secret" "$nevisadmin4_namespace"
}

# Upgrade the nevisadmin4 image version and the nevisadmin4-dbschema-wait image version in the statefulset
upgradeImageVersions() {
    command="kubectl set image statefulset/nevisadmin4 nevisadmin4=$container_registry/$image_prefix/nevisadmin4:$image_version nevisadmin4-dbschema-wait=$container_registry/$image_prefix/nevisadmin4-dbschema:$image_version -n $nevisadmin4_namespace"
    ./lib/msg.sh "Upgrading the nevisAdmin4 image version and the nevisadmin4-dbschema-wait image version: $command"
    eval "$command"

    # From https://github.com/kubernetes/kubernetes/issues/79606#issuecomment-779779928 (kubectl wait does not work for statefulsets)
    waitCommand="kubectl rollout status --watch --timeout=10m statefulset/nevisadmin4 -n $nevisadmin4_namespace"
    ./lib/msg.sh "Waiting for the nevisadmin4 statefulset to be finished: $waitCommand"
    eval "$waitCommand"
}

restartNevisadmin() {
    command="kubectl rollout restart statefulset/nevisadmin4 -n $nevisadmin4_namespace"
    ./lib/msg.sh "Restarting nevisAdmin4: $command"
    eval "$command"
}

# Copy the current nevisadmin4 statefulset to the tmp folder.
readCurrentStatefulSet() {
    getStatefulSetCommand="kubectl get statefulset nevisadmin4 -n $nevisadmin4_namespace -o yaml > lib/tmp/oldStatefulset.yaml"
    ./lib/msg.sh "Backing up the current statefulset of nevisAdmin4: $getStatefulSetCommand"
    eval "$getStatefulSetCommand"
}

# Roll back the nevisadmin4 image version and the nevisadmin4-dbschema-wait image version in the statefulset to the one we backed up.
# These versions can be seen in lib/tmp/oldNevisadmin4Images.yaml
rollbackImageVersions() {
    oldNevisadminImageVersion="$(lib/yq_linux_amd64 'e' ".nevisadmin" 'lib/tmp/oldNevisadmin4Images.yaml')"
    oldDbSchemaWaitImageVersion="$(lib/yq_linux_amd64 'e' ".db-schema-wait" 'lib/tmp/oldNevisadmin4Images.yaml')"
    command="kubectl set image statefulset/nevisadmin4 nevisadmin4=$oldNevisadminImageVersion nevisadmin4-dbschema-wait=$oldDbSchemaWaitImageVersion -n $nevisadmin4_namespace"
    ./lib/msg.sh "Downgrading the nevisadmin4 image version and the nevisadmin4-dbschema-wait image version: $command"
    eval "$command"

    # From https://github.com/kubernetes/kubernetes/issues/79606#issuecomment-779779928 (kubectl wait does not work for statefulsets)
    waitCommand="kubectl rollout status --watch --timeout=10m statefulset/nevisadmin4 -n $nevisadmin4_namespace"
    ./lib/msg.sh "Waiting for the nevisadmin4 statefulset to be finished: $waitCommand"
    eval "$waitCommand"
}

rollback() {
    rollbackImageVersions
}

# Copy the current version number of nevisadmin4 alongside with it's name and repo name into lib/tmp/oldNevisadmin4Images.yaml
# in case it has to be rolled back
backupNevisadminImageVersion() {
    oldImageIndex="$(lib/yq_linux_amd64 'e' '.spec.template.spec.containers.[] | select(.name == "nevisadmin4") | path | .[-1]' 'lib/tmp/oldStatefulset.yaml')"
    oldImage="$(lib/yq_linux_amd64 'e' ".spec.template.spec.containers[$oldImageIndex].image" 'lib/tmp/oldStatefulset.yaml')"
    ./lib/msg.sh "Backing up current nevisadmin4 image: $oldImage"
    lib/yq_linux_amd64 'e' ".nevisadmin = \"$oldImage\"" 'lib/tmp/oldNevisadmin4Images.yaml' '--inplace'
}

# Copy the current version number of nevisadmin4-dbschema-wait alongside with it's name and repo name into lib/tmp/oldNevisadmin4Images.yaml
# in case it has to be rolled back
backupDbSchemaWaitImageVersion() {
    oldImageIndex="$(lib/yq_linux_amd64 'e' '.spec.template.spec.initContainers.[] | select(.name == "nevisadmin4-dbschema-wait") | path | .[-1]' 'lib/tmp/oldStatefulset.yaml')"
    oldImage="$(lib/yq_linux_amd64 'e' ".spec.template.spec.initContainers[$oldImageIndex].image" 'lib/tmp/oldStatefulset.yaml')"
    ./lib/msg.sh "Backing up current nevisadmin4-dbschema-wait image: $oldImage"
    lib/yq_linux_amd64 'e' ".db-schema-wait = \"$oldImage\"" 'lib/tmp/oldNevisadmin4Images.yaml' '--inplace'
}

backup() {
    if [[ ! -f "lib/tmp/oldNevisadmin4Images.yaml" ]]; then
        lib/yq_linux_amd64 eval --null-input '.nevisadmin = "" | .db-schema-wait = ""' >lib/tmp/oldNevisadmin4Images.yaml
    fi
    readCurrentStatefulSet
    backupNevisadminImageVersion
    backupDbSchemaWaitImageVersion
}

main() {
    parseParams "$@"

    upDowngrade=""
    [[ $isRollback == true ]] && upDowngrade="downgrade" || upDowngrade="upgrade"

    ./lib/msg.sh ""
    ./lib/msg.sh "-------- Nevisadmin $upDowngrade ---------"
    ./lib/msg.sh "This step ${upDowngrade}s the nevisadmin4 image version and the nevisadmin4-dbschema-wait image version in the statefulset."
    ./lib/msg.sh "Then, it restarts nevisadmin4."

    read -p "$upDowngrade the nevisAdmin4 instance? [y/n] " -n 1 -r
    printf '\n'
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        return
    fi

    runChecks
    if [[ $isRollback == true ]]; then
        rollback
        restartNevisadmin
        ./lib/msg.sh "Rolled back Nevisadmin upgrade."
        return
    fi
    backup
    upgradeImageVersions
    restartNevisadmin
    ./lib/msg.sh "Nevisadmin upgrade completed."
}

main "$@"
