#!/usr/bin/env bash

set -Eeuo pipefail

nevisoperator_namespace=''
image_prefix=''
image_version=''
container_registry=''
isRollback=false

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

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

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

    image_version=$(lib/yq_linux_amd64 'e' '.versions.nevisoperator' '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 "get deployment" "$nevisoperator_namespace"
    ./lib/check-permissions.sh "patch deployment" "$nevisoperator_namespace"
}

# Copy the current operator deployment to the tmp folder.
readCurrentDeployment() {
    getDeploymentCommand="kubectl get deployment nevisoperator-controller-manager -n $nevisoperator_namespace -o yaml > lib/tmp/oldOperatorDeployment.yaml"
    ./lib/msg.sh "Backing up the current deployment for nevisOperator: $getDeploymentCommand"
    eval "$getDeploymentCommand"
}

# Upgrade the nevisoperator image version in the deployment
upgradeImageVersions() {
    command="kubectl set image deployment/nevisoperator-controller-manager manager=$container_registry/$image_prefix/nevisoperator:$image_version -n $nevisoperator_namespace"
    ./lib/msg.sh "Upgrading the nevisoperator image version: $command"
    eval "$command"

    waitCommand="kubectl rollout status -n $nevisoperator_namespace deployment/nevisoperator-controller-manager --timeout=5m"
    ./lib/msg.sh "Waiting for the operator deployment to be ready: $waitCommand"
    eval "$waitCommand"
}

# Copy the current version number of operator alongside with it's name and repo name into lib/tmp/oldOperatorImages.yaml
# in case it has to be rolled back
backupOperatorImageVersion() {
    if [[ ! -f "lib/tmp/oldOperatorImages.yaml" ]]; then
        lib/yq_linux_amd64 eval --null-input '.manager = ""' >lib/tmp/oldOperatorImages.yaml
    fi
    oldImageIndex="$(lib/yq_linux_amd64 'e' '.spec.template.spec.containers.[] | select(.name == "manager") | path | .[-1]' 'lib/tmp/oldOperatorDeployment.yaml')"
    oldImage="$(lib/yq_linux_amd64 'e' ".spec.template.spec.containers[$oldImageIndex].image" 'lib/tmp/oldOperatorDeployment.yaml')"
    ./lib/msg.sh "Backing up current operator image: $oldImage"
    lib/yq_linux_amd64 'e' ".manager = \"$oldImage\"" 'lib/tmp/oldOperatorImages.yaml' '--inplace'
}

# Roll back the operator image version in the deployment to the one we backed up.
# These versions can be seen in lib/tmp/oldOperatorDeployment.yaml
rollbackImageVersions() {
    oldManagerImageVersion="$(lib/yq_linux_amd64 'e' ".manager" 'lib/tmp/oldOperatorImages.yaml')"
    command="kubectl set image deployment/nevisoperator-controller-manager manager=$oldManagerImageVersion -n $nevisoperator_namespace"
    ./lib/msg.sh "Downgrading the operator image version: $command"
    eval "$command"

    waitCommand="kubectl rollout status -n $nevisoperator_namespace deployment/nevisoperator-controller-manager --timeout=5m"
    ./lib/msg.sh "Waiting for the operator deployment to be ready: $waitCommand"
    eval "$waitCommand"
}

main() {
    parseParams "$@"

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

    ./lib/msg.sh ""
    ./lib/msg.sh "-------- Operator $upDowngrade ---------"
    ./lib/msg.sh "This step ${upDowngrade}s the nevisoperator image version in the deployment."

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

    runChecks
    if [[ $isRollback == true ]]; then
        rollbackImageVersions
        ./lib/msg.sh "Rolled back Operator upgrade."
        return
    fi
    readCurrentDeployment
    backupOperatorImageVersion
    upgradeImageVersions
    ./lib/msg.sh "Operator upgrade completed."
}

main "$@"
