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

validate_nginx() {
  declare desc="validate entire nginx config"
  set +e
  sudo /usr/sbin/nginx -t > /dev/null 2>&1
  local exit_code=$?
  set -e
  if [[ "$exit_code" -ne "0" ]]; then
    sudo /usr/sbin/nginx -t
    exit "$exit_code"
  fi
}

restart_nginx() {
  declare desc="restart nginx for given distros"
  case "$DOKKU_DISTRO" in
    debian)
      sudo /usr/sbin/invoke-rc.d nginx reload > /dev/null
      ;;

    ubuntu)
      sudo /etc/init.d/nginx reload > /dev/null
      ;;

    opensuse)
      sudo /sbin/service nginx reload > /dev/null
      ;;

    arch)
      sudo /usr/bin/systemctl reload nginx
	  ;;
  esac
}

nginx_logs() {
  declare desc="display app nginx logs"
  local APP="$2"; verify_app_name "$APP"
  local NGINX_LOGS_TYPE=${1#nginx:}
  local NGINX_LOGS_TYPE=${NGINX_LOGS_TYPE%-logs}
  local NGINX_LOGS_PATH="/var/log/nginx/$APP-$NGINX_LOGS_TYPE.log"

  if [[ $3 == "-t" ]]; then
    local NGINX_LOGS_ARGS="-F"
  else
    local NGINX_LOGS_ARGS="-n 20"
  fi

  tail "$NGINX_LOGS_ARGS" "$NGINX_LOGS_PATH"
}

configure_nginx_ports() {
  declare desc="configure nginx listening ports"
  local APP=$1; verify_app_name "$APP"
  local RAW_TCP_PORTS="$(get_app_raw_tcp_ports "$APP")"
  local DOKKU_NGINX_PORT=$(config_get "$APP" DOKKU_NGINX_PORT)
  local DOKKU_NGINX_SSL_PORT=$(config_get "$APP" DOKKU_NGINX_SSL_PORT)
  local IS_APP_VHOST_ENABLED="$(is_app_vhost_enabled "$APP")"

  if [[ -z "$DOKKU_NGINX_PORT" ]]; then
    if [[ -z "$RAW_TCP_PORTS" ]]; then
      if [[ "$IS_APP_VHOST_ENABLED" == "false" ]]; then
        dokku_log_info1 "no nginx port set. setting to random open high port"
        local NGINX_PORT=$(get_available_port)
      else
        local NGINX_PORT=80
      fi
    fi
    if [[ -n "$NGINX_PORT" ]]; then
      config_set --no-restart "$APP" DOKKU_NGINX_PORT="${NGINX_PORT}"
    fi
  fi

  if (is_ssl_enabled "$APP") && [[ -z "$DOKKU_NGINX_SSL_PORT" ]] && [[ -z "$RAW_TCP_PORTS" ]]; then
    if [[ "$IS_APP_VHOST_ENABLED" == "false" ]]; then
      dokku_log_info1 "no nginx ssl port set. setting to random open high port"
      local NGINX_SSL_PORT=$(get_available_port)
    else
      local NGINX_SSL_PORT=443
    fi
    config_set --no-restart "$APP" DOKKU_NGINX_SSL_PORT="${NGINX_SSL_PORT}"
  fi
}

validate_ssl_domains() {
  declare desc="check configured domains against SSL cert contents and show warning if mismatched"
  local APP=$1; verify_app_name "$APP"
  local SSL_HOSTNAME=$(get_ssl_hostnames "$APP")
  local SSL_HOSTNAME_REGEX=$(echo "$SSL_HOSTNAME" | xargs | sed 's|\.|\\.|g' | sed 's/\*/\[^\.\]\*/g' | sed 's/ /|/g')
  local domain

  if ! (egrep -q "^${SSL_HOSTNAME_REGEX}$" "$VHOST_PATH" &> /dev/null); then
    dokku_log_info1 "No matching configured domains for $APP found in SSL certificate. Your app will show as insecure in a browser if accessed via SSL"
    dokku_log_info1 "Please add appropriate domains via the dokku domains command"
    [[ -n "$NONSSL_VHOSTS" ]] && dokku_log_info1 "Configured domains for app:"
    for domain in $(echo "$NONSSL_VHOSTS"| xargs); do
      dokku_log_info2 "$domain"
    done
    [[ -n "$SSL_HOSTNAME" ]] && dokku_log_info1 "Domains found in SSL certificate:"
    for domain in $(echo "$SSL_HOSTNAME" | xargs); do
      dokku_log_info2 "$domain"
    done
  fi
}

get_custom_nginx_template() {
  declare desc="attempts to copy custom nginx template from app image"
  local APP="$1"; verify_app_name "$APP"
  local DESTINATION="$2"
  local IMAGE_TAG="$(get_running_image_tag "$APP")"
  local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG")
  local NGINX_TEMPLATE_NAME="nginx.conf.sigil"

  copy_from_image "$IMAGE" "$NGINX_TEMPLATE_NAME" "$DESTINATION" 2>/dev/null || true
}

nginx_build_config() {
  declare desc="build nginx config to proxy app containers using sigil"
  local APP="$1"; verify_app_name "$APP"
  local DOKKU_APP_LISTEN_PORT="$2"; local DOKKU_APP_LISTEN_IP="$3"
  local VHOST_PATH="$DOKKU_ROOT/$APP/VHOST"; local URLS_PATH="$DOKKU_ROOT/$APP/URLS"
  local NGINX_TEMPLATE_NAME="nginx.conf.sigil"
  local DEFAULT_NGINX_TEMPLATE="$PLUGIN_AVAILABLE_PATH/nginx-vhosts/templates/$NGINX_TEMPLATE_NAME"
  local NGINX_TEMPLATE="$DEFAULT_NGINX_TEMPLATE"; local SCHEME=http
  local NGINX_TEMPLATE_SOURCE="built-in"; local APP_SSL_PATH="$DOKKU_ROOT/$APP/tls"
  local RAW_TCP_PORTS="$(get_app_raw_tcp_ports "$APP")"

  local DOKKU_DISABLE_PROXY=$(config_get "$APP" DOKKU_DISABLE_PROXY)
  local IS_APP_VHOST_ENABLED=$(is_app_vhost_enabled "$APP")

  if [[ -z "$DOKKU_DISABLE_PROXY" ]]; then
    if [[ -z "$DOKKU_APP_LISTEN_PORT" ]] && [[ -z "$DOKKU_APP_LISTEN_IP" ]]; then
      shopt -s nullglob
      local DOKKU_APP_IP_FILE
      for DOKKU_APP_IP_FILE in $DOKKU_ROOT/$APP/IP.web.*; do
        local DOKKU_APP_PORT_FILE="${DOKKU_APP_IP_FILE//IP/PORT}"
        local DOKKU_APP_LISTENER_IP=$(< "$DOKKU_APP_IP_FILE")
        local DOKKU_APP_LISTENER_PORT=$(< "$DOKKU_APP_PORT_FILE")

        if [[ -z "$RAW_TCP_PORTS" ]]; then
          local DOKKU_APP_LISTENERS+=" $DOKKU_APP_LISTENER_IP:$DOKKU_APP_LISTENER_PORT "
        else
          local DOKKU_APP_LISTENERS+=" $DOKKU_APP_LISTENER_IP "
        fi
        local DOKKU_APP_LISTENERS=$(echo "$DOKKU_APP_LISTENERS" | xargs)
      done
      shopt -u nullglob
    elif [[ -n "$DOKKU_APP_LISTEN_PORT" ]] && [[ -n "$DOKKU_APP_LISTEN_IP" ]]; then
      local PASSED_LISTEN_IP_PORT=true
    fi

    local NGINX_BUILD_CONFIG_TMP_WORK_DIR=$(mktemp -d /tmp/dokku_nginx_template.XXXXX)
    local NGINX_CONF=$(mktemp --tmpdir="${NGINX_BUILD_CONFIG_TMP_WORK_DIR}" "nginx.conf.XXXXXX")
    local CUSTOM_NGINX_TEMPLATE="$NGINX_BUILD_CONFIG_TMP_WORK_DIR/$NGINX_TEMPLATE_NAME"
    # shellcheck disable=SC2086
    trap 'rm -rf $NGINX_CONF $NGINX_BUILD_CONFIG_TMP_WORK_DIR > /dev/null' RETURN INT TERM EXIT

    get_custom_nginx_template "$APP" "$CUSTOM_NGINX_TEMPLATE"
    if [[ -f "$CUSTOM_NGINX_TEMPLATE" ]]; then
      dokku_log_info1 'Overriding default nginx.conf with detected nginx.conf.sigil'
      local NGINX_TEMPLATE="$CUSTOM_NGINX_TEMPLATE"
      local NGINX_TEMPLATE_SOURCE="app-supplied"
    fi

    # setup nginx listen ports
    configure_nginx_ports "$APP"
    local NGINX_PORT=$(config_get "$APP" DOKKU_NGINX_PORT)
    local NGINX_SSL_PORT=$(config_get "$APP" DOKKU_NGINX_SSL_PORT)

    local NONSSL_VHOSTS=$(get_app_domains "$APP")
    local NOSSL_SERVER_NAME=$(echo "$NONSSL_VHOSTS" | xargs)
    if is_ssl_enabled "$APP"; then
      local SSL_INUSE=true; local SCHEME=https
      validate_ssl_domains "$APP"
      local SSL_HOSTNAME=$(get_ssl_hostnames "$APP")
      local SSL_HOSTNAME_REGEX=$(echo "$SSL_HOSTNAME" | xargs | sed 's|\.|\\.|g' | sed 's/\*/\[^\.\]\*/g' | sed 's/ /|/g')

      if [[ "$IS_APP_VHOST_ENABLED" == "true" ]]; then
        local SSL_VHOSTS=$(egrep "^${SSL_HOSTNAME_REGEX}$" "$VHOST_PATH" || true)
      else
        local SSL_VHOSTS=$(< "$DOKKU_ROOT/HOSTNAME")
      fi
      local SSL_SERVER_NAME=$(echo "$SSL_VHOSTS" | xargs)
    fi
    eval "$(config_export app "$APP")"
    local SIGIL_PARAMS=(-f $NGINX_TEMPLATE APP="$APP" DOKKU_ROOT="$DOKKU_ROOT"
          NOSSL_SERVER_NAME="$NOSSL_SERVER_NAME"
          DOKKU_APP_LISTENERS="$DOKKU_APP_LISTENERS"
          PASSED_LISTEN_IP_PORT="$PASSED_LISTEN_IP_PORT"
          DOKKU_APP_LISTEN_PORT="$DOKKU_APP_LISTEN_PORT" DOKKU_APP_LISTEN_IP="$DOKKU_APP_LISTEN_IP"
          APP_SSL_PATH="$APP_SSL_PATH" SSL_INUSE="$SSL_INUSE" SSL_SERVER_NAME="$SSL_SERVER_NAME"
          NGINX_PORT="$NGINX_PORT" NGINX_SSL_PORT="$NGINX_SSL_PORT" RAW_TCP_PORTS="$RAW_TCP_PORTS")

    # execute sigil template processing
    xargs -i echo "-----> Configuring {}...(using $NGINX_TEMPLATE_SOURCE template)" <<< "$(echo "${SSL_VHOSTS}" "${NONSSL_VHOSTS}" | tr ' ' '\n' | sort -u)"
    # echo "sigil ${SIGIL_PARAMS[@]}"
    sigil "${SIGIL_PARAMS[@]}" > "$NGINX_CONF"

    if is_deployed "$APP"; then
      dokku_log_info1 "Creating $SCHEME nginx.conf"
      mv "$NGINX_CONF" "$DOKKU_ROOT/$APP/nginx.conf"
    else
      dokku_log_info1 "App $APP has not been deployed. Skipping nginx config creation"
      rm -f "$NGINX_CONF"
    fi

    if is_deployed "$APP"; then
      dokku_log_info1 "Running nginx-pre-reload"
      plugn trigger nginx-pre-reload "$APP" "$DOKKU_APP_LISTEN_PORT" "$DOKKU_APP_LISTEN_IP"

      dokku_log_verbose "Reloading nginx"
      validate_nginx && restart_nginx
    fi

    if ([[ -n "$NONSSL_VHOSTS" ]] || [[ -n "$SSL_VHOSTS" ]]) && [[ "$IS_APP_VHOST_ENABLED" == "true" ]]; then
      echo "# THIS FILE IS GENERATED BY DOKKU - DO NOT EDIT, YOUR CHANGES WILL BE OVERWRITTEN" > "$URLS_PATH"
      xargs -i echo "$SCHEME://{}" <<< "$(echo "${SSL_VHOSTS}" "${NONSSL_VHOSTS}" | tr ' ' '\n' | sort -u)" >> "$URLS_PATH"
    fi
  else
    # note because this clause is long. if $DOKKU_DISABLE_PROXY is set:
    dokku_log_info1 "nginx support is disabled for app ($APP)."
    if [[ -f "$DOKKU_ROOT/$APP/nginx.conf" ]]; then
      dokku_log_info1 "deleting nginx.conf"
      rm "$DOKKU_ROOT/$APP/nginx.conf"

      if is_deployed "$APP"; then
        dokku_log_info1 "reloading nginx after nginx.conf deletion"
        validate_nginx && restart_nginx
      fi
    fi
  fi
}
