#!/usr/bin/env bash

set -Eeou pipefail
# script prepares environment variables relevant for the current context

source scripts/funcs/errors

script_name=$(readlink -f "${BASH_SOURCE[0]}")
script_dir=$(dirname "${script_name}")

destination_envs_dir="${script_dir}/../../.generated"
destination_envs_file="${destination_envs_dir}/context"

contexts_dir="scripts/dev/contexts"

context="${1:-}"
additional_override="${2:-}"

if [[ "${context}" == "" ]]; then
  # shellcheck disable=SC2012
  contexts=$(ls -1 "${contexts_dir}")
  if [[ -f "${destination_envs_dir}/.current_context" ]]; then
    current_context=$(cat "${destination_envs_dir}/.current_context")
    contexts=$(printf "${current_context}\n%s" "${contexts}")
  fi
  context="$(fzf --sort <<< "${contexts}")"
fi

if [[ "${additional_override}" != *"private-context-"* && -n "${additional_override}" ]]; then
  # shellcheck disable=SC2010
  additional_override="$(ls -1 "${contexts_dir}" | grep "private-context-" | fzf --sort)"
fi

context_file="${contexts_dir}/${context}"
local_development_default_file="${contexts_dir}/local-defaults-context"
override_context_file="${contexts_dir}/private-context-override"
additional_override_file="${contexts_dir}/${additional_override}"

mkdir -p "${destination_envs_dir}"

if [[ ! -f "${context_file}" ]]; then
	fatal "Cannot switch context: File ${context_file} does not exist."
fi

echo "Switching context to: ${context}"


# This means we are running on evergreen, in this case we need the environment variables from evg expansions.
# If running locally, we don't need them since they are defined in the private-context already, so we don't need
# any kind of current env var expansions
if [ -n "${EVR_TASK_ID-}" ]; then
  # shellcheck disable=SC1090
    source "${context_file}"
    # shellcheck disable=SC2207
    export CURRENT_VARIANT_CONTEXT="${context}"
    current_envs=$(export -p)
else
  # env -i makes sure to start the shell with an empty shell, such that we only save into context.env the env vars we have
  # defined.
  base_command="source ${local_development_default_file} && source ${context_file}"
  if [ -n "${additional_override}" ]; then
      echo "Using additional override file: ${additional_override_file}."
      base_command+=" && source ${additional_override_file}"
  elif [ -f "${override_context_file}" ]; then
      echo "Using override file: ${override_context_file}. If you do not want to use one, remove the file or its contents."
      base_command+=" && source ${override_context_file}"
  fi
  # Execute the command in a clean environment and capture exported variables
  # Let's use our PATH as a base to have utilities available.
  current_envs=$(env -i PWD="${PWD}" PATH="${PATH}" CURRENT_VARIANT_CONTEXT="${context}" bash -c "${base_command} && export -p")

  # `export -p` instead of `env` ensures we can safely re-source variables which we rely on further
  # below like our operator.print.env script
  # eval ensures we only use the exports and don't run the whole script against as done in base_command
  eval "${current_envs}"
fi

# convert declare -x key=value into key=value
# filter out variables that don't have value (missing '=')
current_envs=$(echo "${current_envs[@]}" | grep '=' | sed 's/^declare -x //g' | sed 's/=/=/'| sort | uniq)

echo -e "## This file is automatically generated by switch_context.sh\n## Do not edit it!" > "${destination_envs_file}.env"
# shellcheck disable=SC2129
echo -e "## Regenerated at $(date)\n" >> "${destination_envs_file}.env"
echo "${current_envs}" >> "${destination_envs_file}.env"

# Below is a list of special cases of variables that are called the same in EVG and local context.
# This piece should probably be refactored as it's super easy to make a mistake and shadow the proper variable.
echo "workdir=\"${workdir:-.}\"" >> "${destination_envs_file}.env"

# We need to tail +5 lines due to above generated comment.
awk '{print "export " $0}' < "${destination_envs_file}".env | tail -n +5 > "${destination_envs_file}".export.env

scripts/dev/print_operator_env.sh | sort | uniq >"${destination_envs_file}.operator.env"
awk '{print "export " $0}' < "${destination_envs_file}".operator.env > "${destination_envs_file}".operator.export.env

echo -n "${context}" > "${destination_envs_dir}/.current_context"

echo "Generated env files in $(readlink -f "${destination_envs_dir}"):"
# shellcheck disable=SC2010
ls -l1 "${destination_envs_dir}" | grep "context"

# Prefer kubectl from bin directory if it exists, otherwise use system kubectl
KUBECTL_CMD="kubectl"
if [[ -n "${PROJECT_DIR:-}" && -x "${PROJECT_DIR}/bin/kubectl" ]]; then
    KUBECTL_CMD="${PROJECT_DIR}/bin/kubectl"
fi

if [[ "${KUBECTL_CMD}" != "kubectl" ]] || which kubectl > /dev/null; then
    if [ "${CLUSTER_NAME-}" ]; then
        # The convention: the cluster name must match the name of kubectl context
        # We expect this not to be true if kubernetes cluster is still to be created (minikube/kops)
        if ! "${KUBECTL_CMD}" config use-context "${CLUSTER_NAME}"; then
            echo "Warning: failed to switch kubectl context to: ${CLUSTER_NAME}"
            echo "Does a matching Kubernetes context exist?"
        fi

        # Setting the default namespace for current context
        "${KUBECTL_CMD}" config set-context "$("${KUBECTL_CMD}" config current-context)" "--namespace=${NAMESPACE}" &>/dev/null || true

        # shellcheck disable=SC2153
        echo "Current context: ${context} (kubectl context: ${CLUSTER_NAME}), namespace=${NAMESPACE}"
    fi
else
    echo "Kubectl doesn't exist, skipping setting the context"
fi
