#!/usr/bin/env bash
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"

config_export() {
  declare desc="returns export command for config variable of specified type (app/global)"
  local CONFIG_TYPE="$1"
  local APP="$2"
  local ENV_FILE="$DOKKU_ROOT/$APP/ENV"

  [[ $CONFIG_TYPE == "global" ]] && local ENV_FILE="$DOKKU_ROOT/ENV"
  [[ ! -f $ENV_FILE ]] && return 0
  [[ ! -s $ENV_FILE ]] && return 0

  local VARS=$(grep -Eo "export ([a-zA-Z_][a-zA-Z0-9_]*=.*)" "$ENV_FILE" | cut -d" " -f2-)
  echo "$VARS" | awk '{print "export " $0}'
  return 0
}

get_sanitized_config_args() {
  local desc="return sanitized arguments for config plugin"
  local SANITIZED_ARGS=("$@")

  SANITIZED_ARGS=("${SANITIZED_ARGS[@]//--global/}")
  SANITIZED_ARGS=("${SANITIZED_ARGS[@]//--no-restart/}")
  SANITIZED_ARGS=("${SANITIZED_ARGS[@]//--export/}")
  SANITIZED_ARGS=("${SANITIZED_ARGS[@]//--shell/}")

  echo "${SANITIZED_ARGS[@]}"
}

config_parse_args() {
  declare desc="parse config plugin args"
  unset APP ENV_FILE DOKKU_CONFIG_TYPE DOKKU_CONFIG_RESTART DOKKU_CONFIG_EXPORT

  for var; do
    if [[ "$var" == "--global" ]]; then
      ENV_FILE="$DOKKU_ROOT/ENV"
      DOKKU_CONFIG_TYPE="global"
      DOKKU_CONFIG_RESTART=false
    fi
    if [[ "$var" == "--no-restart" ]]; then
      DOKKU_CONFIG_RESTART=false
    fi
    if [[ "$var" == "--export" ]]; then
      DOKKU_CONFIG_EXPORT=true
    fi
    if [[ "$var" == "--shell" ]]; then
      DOKKU_CONFIG_SHELL=true
    fi
  done

  local SANITIZED_ARGS=($(get_sanitized_config_args "$@"))
  set -- "${SANITIZED_ARGS[@]}"

  DOKKU_CONFIG_TYPE=${DOKKU_CONFIG_TYPE:="app"}
  DOKKU_CONFIG_RESTART=${DOKKU_CONFIG_RESTART:=true}

  if [[ "$DOKKU_CONFIG_TYPE" == "app" ]]; then
    if [[ -z $2 ]]; then
      dokku_log_fail "Please specify an app to run the command on"
    else
      verify_app_name "$2"
      APP=${APP:="$2"}
      ENV_FILE=${ENV_FILE:="$DOKKU_ROOT/$APP/ENV"}
    fi
  fi
  export APP ENV_FILE DOKKU_CONFIG_TYPE DOKKU_CONFIG_RESTART DOKKU_CONFIG_EXPORT
}

config_create () {
  declare desc="create config env file"
  local ENV_FILE=$1
  [[ -f $ENV_FILE ]] || touch "$ENV_FILE"
}

config_styled_hash () {
  declare desc="internal config hash"
  local vars="$1"
  local prefix="$2"
  local longest=""

  while read -r word; do
    local KEY=$(echo "$word" | cut -d"=" -f1)
    if [[ ${#KEY} -gt ${#longest} ]]; then
      local longest=$KEY
    fi
  done <<< "$vars"

  while read -r word; do
    local KEY=$(echo "$word" | cut -d"=" -f1)
    local VALUE=$(echo "$word" | cut -d"=" -f2- | sed -e "s/^'//" -e "s/'$//" -e "s/\$$//g")

    local num_zeros=$((${#longest} - ${#KEY}))
    local zeros=" "
    while [[ $num_zeros -gt 0 ]]; do
      local zeros="$zeros "
      local num_zeros=$((num_zeros - 1))
    done
    echo "$prefix$KEY:$zeros$VALUE"
  done <<< "$vars"
}

config_write() {
  declare desc="writes config vars out to appropriate file path"
  local ENV_TEMP="$1"
  local ENV_FILE_TEMP="${ENV_FILE}.tmp"

  echo "$ENV_TEMP" | sed '/^$/d' | sort > "$ENV_FILE_TEMP"
  if ! cmp -s "$ENV_FILE" "$ENV_FILE_TEMP"; then
    cp -f "$ENV_FILE_TEMP" "$ENV_FILE"
    chmod 600 "$ENV_FILE"
  fi
  rm -f "$ENV_FILE_TEMP"
}

config_all() {
  declare desc="print or export config vars"
  [[ "$1" == "config" ]] || set -- "config" "$@"
  config_parse_args "$@"
  local SANITIZED_ARGS=($(get_sanitized_config_args "$@"))
  set -- "${SANITIZED_ARGS[@]}"

  config_create "$ENV_FILE"
  [[ $DOKKU_CONFIG_EXPORT ]] && config_export "$DOKKU_CONFIG_TYPE" "$APP" && return 0

  [[ $APP ]] && local DOKKU_CONFIG_TYPE=$APP
  [[ ! -s $ENV_FILE ]] && dokku_log_fail "no config vars for $DOKKU_CONFIG_TYPE"

  local VARS=$(grep -Eo "export ([a-zA-Z_][a-zA-Z0-9_]*=.*)" "$ENV_FILE" | cut -d" " -f2-)

  [[ $DOKKU_CONFIG_SHELL ]] && echo "$VARS" && return 0

  dokku_log_info2_quiet "$DOKKU_CONFIG_TYPE config vars"
  config_styled_hash "$VARS"
}

config_get() {
  declare desc="get value of given config var"
  [[ "$1" == "config:get" ]] || set -- "config:get" "$@"
  config_parse_args "$@"
  local SANITIZED_ARGS=($(get_sanitized_config_args "$@"))
  set -- "${SANITIZED_ARGS[@]}"

  if [[ -z $2 ]]; then
    echo "Usage: dokku config:get APP KEY"
    echo "Must specify KEY."
    exit 1
  fi

  config_create "$ENV_FILE"
  if [[ ! -s $ENV_FILE ]]; then
    return 0
  fi

  local KEY="${*: -1}"

  grep -Eo "export ([a-zA-Z_][a-zA-Z0-9_]*=.*)" "$ENV_FILE" | grep "^export $KEY=" | cut -d"=" -f2- | sed -e "s/^'//" -e "s/'$//"
}

config_set() {
  declare desc="set value of given config var"
  [[ "$1" == "config:set" ]] || set -- "config:set" "$@"
  config_parse_args "$@"

  if [[ -z "${*:3}" ]]; then
    echo "Usage: dokku config:set APP KEY1=VALUE1 [KEY2=VALUE2 ...]"
    echo "Whitespaces need to be escaped, i.e. KEY=\"VAL\ WITH\ SPACES\""
    echo "Must specify KEY and VALUE to set."
    exit 1
  fi

  config_create "$ENV_FILE"
  local ENV_ADD=""
  local ENV_TEMP=$(cat "${ENV_FILE}")
  local RESTART_APP=false
  shift 2

  for var; do
    if [[ $var == "--global" ]] || [[ $var == "--no-restart" ]] || ([[ $APP ]] && [[ $var == "$APP" ]]); then
      shift 1
    elif [[ $var != *"="* ]]; then
      echo "Usage: dokku config:set APP KEY1=VALUE1 [KEY2=VALUE2 ...]"
      echo "Whitespaces need to be escaped, i.e. KEY=\"VAL\ WITH\ SPACES\""
      echo "Must specify KEY and VALUE to set."
      exit 1
    fi
  done

  for var; do
    local KEY=$(echo ${var} | cut -d"=" -f1)
    local VALUE=$(echo ${var} | cut -d"=" -f2-)

    if [[ $KEY =~ [a-zA-Z_][a-zA-Z0-9_]* ]]; then
      local RESTART_APP=true
      local ENV_TEMP=$(echo "${ENV_TEMP}" | sed "/^export $KEY=/ d")
      local ENV_TEMP="${ENV_TEMP}
export $KEY='$VALUE'"
      local ENV_ADD=$(echo -e "${ENV_ADD}" | sed "/^$KEY=/ d")
      local ENV_ADD="${ENV_ADD}$
${var}"
    fi
  done
  local ENV_ADD=$(echo "$ENV_ADD" | tail -n +2) #remove first empty line

  if [[ $RESTART_APP ]]; then
    dokku_log_info1 "Setting config vars"
    config_styled_hash "$ENV_ADD" "       "

    config_write "$ENV_TEMP"
    plugn trigger post-config-update "$APP" "set" "$@"
  fi

  [[ $APP ]] && local DOKKU_APP_RESTORE=$(config_get "$APP" DOKKU_APP_RESTORE || true)
  if [[ "$DOKKU_CONFIG_RESTART" == "true" ]] && [[ "$DOKKU_APP_RESTORE" != 0 ]]; then
    dokku_log_info1 "Restarting app $APP"
    dokku ps:restart "$APP"
  fi
}

config_unset() {
  declare desc="unset given config var"
  [[ "$1" == "config:unset" ]] || set -- "config:unset" "$@"
  config_parse_args "$@"
  local SANITIZED_ARGS=($(get_sanitized_config_args "$@"))
  set -- "${SANITIZED_ARGS[@]}"

  if [[ -z $2 ]]; then
    echo "Usage: dokku config:unset APP KEY1 [KEY2 ...]"
    echo "Must specify KEY to unset."
    exit 1
  fi

  config_create "$ENV_FILE"
  local ENV_TEMP=$(cat "${ENV_FILE}")
  local VARS="${*:2}"

  for var in $VARS; do
    dokku_log_info1 "Unsetting $var"
    local ENV_TEMP=$(echo "${ENV_TEMP}" | sed "/^export $var=/ d")

    config_write "$ENV_TEMP"
  done

  plugn trigger post-config-update "$APP" "unset" "$@"

  [[ $APP ]] && local DOKKU_APP_RESTORE=$(config_get "$APP" DOKKU_APP_RESTORE || true)
  if [[ "$DOKKU_CONFIG_RESTART" == "true" ]] && [[ "$DOKKU_APP_RESTORE" != 0 ]]; then
    dokku_log_info1 "Restarting app $APP"
    dokku ps:restart "$APP"
  fi
}
