# shellcheck shell=bash
# shellcheck source=scripts/shared/lib/source_only
. "${BASH_SOURCE%/*}"/source_only

### Functions ###

function import_image() {
    local orig_image=$1
    local versioned_image="$1:${DEV_VERSION}"
    local local_image="localhost:5000/${orig_image##*/}:${2:-local}"
    if ! docker tag "${versioned_image}" "${local_image}"; then
        # The project doesn't build this image, pull it
        docker pull "${orig_image}:${CUTTING_EDGE}"
        docker tag "${orig_image}:${CUTTING_EDGE}" "${versioned_image}"
        docker tag "${versioned_image}" "${local_image}"
    fi

    docker push "${local_image}"
}

function get_globalip() {
    local svc_name=$1
    local gip
    gip=$(kubectl get svc "$svc_name" -o jsonpath='{.metadata.annotations.submariner\.io/globalIp}')
    if [[ -z "${gip}" ]]; then
        gip=$(kubectl get giip "$svc_name" -o jsonpath='{.status.allocatedIP}')
        if [[ -z "${gip}" ]]; then
            sleep 1
            return 1
        fi
    fi

    echo "$gip"
}

function get_svc_ip() {
    local svc_name=$1
    local svc_ip

    if [[ $globalnet = "true" ]]; then
        svc_ip=$(with_retries 30 get_globalip "${svc_name}")
    else
        svc_ip=$(kubectl --context="$cluster" get svc -l "app=${svc_name}" | awk 'FNR == 2 {print $3}')
    fi

    if [[ -z "$svc_ip" ]]; then
        echo "Failed to get ${svc_name} IP"
        exit 1
    fi

    echo "$svc_ip"
}

function test_connection() {
    local source_pod=$1
    local target_address=$2

    echo "Attempting connectivity between clusters - $source_pod --> $target_address"
    wait_time=30
    start_time=$(date +%s)
    if ! kubectl exec "${source_pod}" -- curl --output /dev/null -m "${wait_time}" --silent --head --fail "${target_address}"; then
        end_time=$(date +%s)
        execution_time=$(( end_time - start_time))
        if [ $execution_time -lt $wait_time ]
        then
           remaining_time=$(( wait_time - execution_time))
           echo "curl returned too soon. Sleeping for $remaining_time secs"
           sleep $remaining_time
        fi
        return 1
    fi

    echo "Connection test was successful!"
}

function connectivity_tests() {
    target_cluster="$1"
    import_image quay.io/submariner/nettest
    deploy_resource "${RESOURCES_DIR}/netshoot.yaml"
    with_context "$target_cluster" deploy_resource "${RESOURCES_DIR}/nginx-demo.yaml"

    local netshoot_pod nginx_svc_ip
    netshoot_pod=$(kubectl get pods -l app=netshoot | awk 'FNR == 2 {print $1}')
    nginx_svc_ip=$(with_context "$target_cluster" get_svc_ip nginx-demo)

    with_retries 5 test_connection "$netshoot_pod" "$nginx_svc_ip"

    remove_resource "${RESOURCES_DIR}/netshoot.yaml"
    with_context "$target_cluster" remove_resource "${RESOURCES_DIR}/nginx-demo.yaml"
}

function verify_gw_status() {
    sleep_duration=6
    # helm doesn't use the operator yet, and connection status is based on the operator object
    if subctl show connections 2>&1 | grep "the server could not find the requested resource"; then
        return 0
    fi

    if ! subctl show connections | grep "connected"; then
       echo "iter: $iteration. Clusters not yet connected. sleeping for $sleep_duration secs"
       sleep $sleep_duration
    else
       return 0
    fi
    return 1
}

function add_subm_gateway_label() {
    [[ ${cluster_subm[$cluster]} = "true" ]] || return 0
    kubectl label node "${cluster}-worker" "submariner.io/gateway=true" --overwrite
}

function del_subm_gateway_label() {
    [[ ${cluster_subm[$cluster]} = "true" ]] || return 0
    kubectl label node "${cluster}-worker" "submariner.io/gateway-" --overwrite
}

function prepare_cluster() {
    [[ ${cluster_subm[$cluster]} = "true" ]] || return 0
    add_subm_gateway_label
}

function deploy_resource() {
    local resource_file=$1
    local resource_name
    resource_name=$(basename "$resource_file" ".yaml")
    kubectl apply -f "${resource_file}"
    echo "Waiting for ${resource_name} pods to be ready."
    kubectl rollout status "deploy/${resource_name}" --timeout="${timeout}"
}

function remove_resource() {
    local resource_file=$1
    kubectl delete -f "$resource_file"
}

function load_deploytool() {
    local deploytool=$1
    local deploy_lib=${SCRIPTS_DIR}/lib/deploy_${deploytool}
    if [[ ! -f $deploy_lib ]]; then
        echo "Unknown deploy method: ${deploytool}"
        exit 1
    fi

    echo "Will deploy submariner using ${deploytool}"
    . "$deploy_lib"
}

function find_submariner_namespace() {
    local namespace
    namespace="$(kubectl get pods --all-namespaces | awk '/submariner/{ print $1 }' | grep -v broker | head -n 1)"
    if [[ "${namespace}" == "" ]]; then
        echo "Could not find a submariner deployment namespace" >&2
        exit 1
    fi
    echo "${namespace}"
}

function reload_pods() {
    local resource_type=$1 # the resource type can be deployment or daemonset
    local resource_name=$2 # the name of the resource
    local namespace
    namespace="$(find_submariner_namespace)"

    kubectl patch -n "${namespace}" "${resource_type}" "${resource_name}" \
              --type='json' \
              -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/imagePullPolicy", "value": "Always" },{"op": "replace", "path": "/spec/template/metadata/labels/modified", "value": "'"$(date +%s)"'"}]'
}
