#!/usr/bin/env bash
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/config"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common-functions"
export SUBCOMMAND_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/subcommands"

fn-help() {
  declare CMD="$1"
  local cmd EXIT_CODE

  if [[ "$CMD" == "help" ]] || [[ "$CMD" == "$PLUGIN_COMMAND_PREFIX:help" ]] || [[ "$CMD" == "$PLUGIN_COMMAND_PREFIX" ]] || [[ "$CMD" == "$PLUGIN_COMMAND_PREFIX:default" ]]; then
    fn-help-all "$@"
    exit 0
  fi

  pushd "$SUBCOMMAND_ROOT" >/dev/null 2>&1
  for cmd in *; do
    if [[ "$CMD" == "${PLUGIN_COMMAND_PREFIX}:$cmd" ]]; then
      "$SUBCOMMAND_ROOT/$cmd" "$@"
      EXIT_CODE="$?"
      exit "$EXIT_CODE"
    fi
  done
  popd >/dev/null 2>&1

  exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
}

fn-help-all() {
  declare CMD="$1" SUBCOMMAND="$2"
  local CMD_OUTPUT BLUE BOLD FULL_OUTPUT NORMAL
  FULL_OUTPUT=true

  if [[ "$CMD" == "$PLUGIN_COMMAND_PREFIX:help" ]] || [[ "$CMD" == "$PLUGIN_COMMAND_PREFIX" ]] || [[ "$CMD" == "$PLUGIN_COMMAND_PREFIX:default" ]]; then
    BOLD="$(fn-help-fancy-tput bold)"
    NORMAL="$(fn-help-fancy-color "\033[m")"
    BLUE="$(fn-help-fancy-color "\033[0;34m")"
    CYAN="$(fn-help-fancy-color "\033[1;36m")"
    if [[ -n "$SUBCOMMAND" ]] && [[ "$SUBCOMMAND" != "--all" ]]; then
      fn-help-contents-subcommand "$SUBCOMMAND" "$FULL_OUTPUT"
      return "$?"
    fi

    echo -e "${BOLD}usage${NORMAL}: dokku ${PLUGIN_COMMAND_PREFIX}[:COMMAND]"
    echo ''
    echo -e "${BOLD}List your $PLUGIN_COMMAND_PREFIX services.${NORMAL}"
    echo ''
    echo -e "${BLUE}Example:${NORMAL}"
    echo ''
    echo "    \$ dokku $PLUGIN_COMMAND_PREFIX:list"
    echo ''
    fn-help-list-example | column -c5 -t -s,
    echo ''
    echo -e "dokku ${BOLD}${PLUGIN_COMMAND_PREFIX}${NORMAL} commands: (get help with ${CYAN}dokku ${PLUGIN_COMMAND_PREFIX}:help SUBCOMMAND${NORMAL})"
    echo ''
    fn-help-contents | sort | column -c2 -t -s,
    echo ''
  elif [[ $(ps -o command= $PPID) == *"--all"* ]]; then
    fn-help-contents
  else
    cat <<help_desc
    $PLUGIN_COMMAND_PREFIX, Plugin for managing $PLUGIN_SERVICE services
help_desc
  fi

  return 0
}

fn-help-contents() {
  pushd "$SUBCOMMAND_ROOT" >/dev/null 2>&1
  for cmd in *; do
    fn-help-contents-subcommand "$cmd" || true
  done
}

fn-help-contents-subcommand() {
  declare SUBCOMMAND="$1" FULL_OUTPUT="$2"
  local HELP_TMPDIR=$(mktemp -d --tmpdir)
  local UNCLEAN_FILE="${HELP_TMPDIR}/cmd-unclean" CLEAN_FILE="${HELP_TMPDIR}/cmd-clean"
  local BOLD CMD_OUTPUT CYAN EXAMPLE LIGHT_GRAY NORMAL
  trap 'rm -rf "$HELP_TMPDIR" > /dev/null' RETURN INT TERM EXIT

  rm -rf "$UNCLEAN_FILE" "$CLEAN_FILE"
  cat "$SUBCOMMAND_ROOT/$SUBCOMMAND" >"$UNCLEAN_FILE"

  fn-help-subcommand-sanitize "$UNCLEAN_FILE" "$CLEAN_FILE"
  if ! is_implemented_command "$SUBCOMMAND"; then
    return 1
  fi

  args="$(fn-help-subcommand-args "$CLEAN_FILE" "$FULL_OUTPUT")"
  SUBCOMMAND=":$SUBCOMMAND"
  [[ "$SUBCOMMAND" == ":default" ]] && SUBCOMMAND=""
  cmd_line="$(echo -e "${SUBCOMMAND} ${args}" | sed -e 's/[[:space:]]*$//')"
  desc="$(grep desc "$CLEAN_FILE" | head -1)"
  eval "$desc"

  BLUE="$(fn-help-fancy-color "\033[0;34m")"
  BOLD="$(fn-help-fancy-tput bold)"
  CYAN="$(fn-help-fancy-color "\033[1;36m")"
  NORMAL="$(fn-help-fancy-color "\033[m")"
  LIGHT_GRAY="$(fn-help-fancy-color "\033[2;37m")"
  LIGHT_RED="$(fn-help-fancy-color "\033[1;31m")"
  CMD_OUTPUT="$(echo -e "    ${PLUGIN_COMMAND_PREFIX}${cmd_line}, ${LIGHT_GRAY}${desc}${NORMAL}")"
  if [[ "$FULL_OUTPUT" != "true" ]]; then
    echo "$CMD_OUTPUT"
    return 0
  fi

  echo -e "${BOLD}usage:${NORMAL} dokku ${PLUGIN_COMMAND_PREFIX}${cmd_line}"
  echo ''
  echo -e "${BOLD}${desc}${NORMAL}"
  echo ''

  ARGS="$(fn-help-subcommand-list-args "$CLEAN_FILE")"
  if [[ -n "$ARGS" ]]; then
    echo -e "${CYAN}arguments:${NORMAL}"
    echo ''
    echo "$ARGS" | column -c2 -t -s,
    echo ''
  fi

  FLAGS="$(fn-help-subcommand-list-flags "$CLEAN_FILE")"
  if [[ -n "$FLAGS" ]]; then
    echo -e "${BLUE}flags:${NORMAL}"
    echo ''
    echo "$FLAGS" | column -c2 -t -s,
    echo ''
  fi

  EXAMPLE="$(fn-help-subcommand-example "$CLEAN_FILE")"
  if [[ -n "$EXAMPLE" ]]; then
    echo -e "${LIGHT_RED}examples:${NORMAL}"
    echo ''
    echo "$EXAMPLE"
    echo ''
  fi

  return 0
}

fn-help-fancy-tput() {
  declare desc="a wrapper around tput"

  if [[ -n "$DOKKU_NO_COLOR" ]] || [[ "$TERM" == "unknown" ]] || [[ "$TERM" == "dumb" ]]; then
    return
  fi

  tput "$@"
}

fn-help-fancy-color() {
  declare desc="a wrapper around colors"

  if [[ -n "$DOKKU_NO_COLOR" ]] || [[ "$TERM" == "unknown" ]] || [[ "$TERM" == "dumb" ]]; then
    return
  fi

  echo "$@"
}

fn-help-list-example() {
  # shellcheck disable=SC2034
  declare desc="return $PLUGIN_COMMAND_PREFIX plugin help content"
  cat <<help_list
      $PLUGIN_SERVICE services
      service-name
help_list
}

fn-help-subcommand-args() {
  declare FUNC_FILE="$1" FULL_OUTPUT="$2"
  local argline arglist args argpos BLUE NORMAL

  if [[ "$FULL_OUTPUT" == "true" ]]; then
    BLUE="$(fn-help-fancy-color "\033[0;34m")"
    NORMAL="$(fn-help-fancy-color "\033[m")"
  fi
  argline=$(grep declare "$FUNC_FILE" | grep -v "declare desc" | head -1 || true)
  arglist=($(echo -e "${argline// /"\n"}" | awk -F= '/=/{print ""$1""}'))
  args=""
  argpos=0
  for arg in "${arglist[@]}"; do
    argpos=$((argpos + 1))
    if [[ "$FULL_OUTPUT" != "true" ]] && [[ "$argpos" == 4 ]]; then
      args+="..."
      break
    fi

    if [[ "$arg" == *_FLAG ]]; then
      arg="${arg/_FLAG/}"
      if [[ $arg == "INFO" ]]; then
        arg="SINGLE_INFO_FLAG"
        args+=" ${BLUE}[--${arg//_/-}]${NORMAL}"
      else
        args+=" ${BLUE}[-${arg:0:1}|--${arg//_/-}]${NORMAL}"
      fi
    elif [[ "$arg" == *_FLAGS_LIST ]]; then
      arg=${arg%_*}
      args+=" [--${arg//_/-}...]"
    elif [[ "$arg" == *_LIST ]]; then
      arg=${arg%_*}
      args+=" <${arg//_/-}...>"
    elif [[ "$arg" == *_OPTIONAL ]]; then
      argName="${arg/_OPTIONAL/}"
      args+=" [<${argName//_/-}>]"
    else
      args+=" <${arg//_/-}>"
    fi
  done
  args=$(echo "$args" | tr "\n" " ")
  # shellcheck disable=SC2001
  echo "${args,,}" | sed -e 's/^[[:space:]]*//'
}

fn-help-subcommand-example() {
  declare FUNC_FILE="$1"
  local EXAMPLE

  EXAMPLE=$(grep "#E" "$FUNC_FILE" | cut -d' ' -f2- || true)
  if [[ -z "$EXAMPLE" ]]; then
    return 0
  fi

  BOLD="$(fn-help-fancy-tput bold)"
  LAST_LINE=""
  LIGHT_GRAY="$(fn-help-fancy-color "\033[2;37m")"
  OTHER_GRAY="$(fn-help-fancy-color "\033[7;37m")"
  NEWLINE=""
  NORMAL="$(fn-help-fancy-color "\033[m")"
  _fn-help-apply-shell-expansion "$EXAMPLE" | while read -r line; do
    line="$(echo "$line" | cut -c 4-)"
    if [[ "$line" == export* ]] || [[ "$line" == dokku* ]]; then
      [[ "$LAST_LINE" == "command" ]] && NEWLINE=""
      [[ "$LAST_LINE" == "sentence" ]] && NEWLINE="\n"
      echo -e "${NEWLINE}    ${LIGHT_GRAY}${line}${NORMAL}"
      LAST_LINE="command"
    else
      [[ "$LAST_LINE" == "command" ]] && NEWLINE="\n"
      [[ "$LAST_LINE" == "sentence" ]] && NEWLINE=""
      [[ "$line" == \>* ]] && line="\n    ${BOLD}${line}${NORMAL}"
      # shellcheck disable=SC2001
      [[ "$line" == "    "* ]] && line="    ${OTHER_GRAY}$(echo "$line" | sed -e 's/^[[:space:]]*//')${NORMAL}"
      echo -e "${NEWLINE}${line}"
      LAST_LINE="sentence"
      NEWLINE="\n"
    fi
  done
}

fn-help-subcommand-list-args() {
  declare FUNC_FILE="$1"
  local EXAMPLE LIGHT_GRAY NORMAL

  FLAGS=$(grep "#A" "$FUNC_FILE" | cut -d'A' -f2- | sed -e 's/^[[:space:]]*//' || true)
  if [[ -z "$FLAGS" ]]; then
    return 0
  fi

  NORMAL="$(fn-help-fancy-color "\033[m")"
  LIGHT_GRAY="$(fn-help-fancy-color "\033[2;37m")"

  _fn-help-apply-shell-expansion "$FLAGS" | while read -r line; do
    echo -e "$(echo "$line" | cut -d',' -f1),${LIGHT_GRAY}$(echo "$line" | cut -d',' -f2-)${NORMAL}"
  done
}

fn-help-subcommand-list-flags() {
  declare FUNC_FILE="$1"
  local EXAMPLE LIGHT_GRAY NORMAL

  FLAGS=$(grep "#F" "$FUNC_FILE" | cut -d'F' -f2- | sed -e 's/^[[:space:]]*//' || true)
  if [[ -z "$FLAGS" ]]; then
    return 0
  fi

  NORMAL="$(fn-help-fancy-color "\033[m")"
  LIGHT_GRAY="$(fn-help-fancy-color "\033[2;37m")"

  _fn-help-apply-shell-expansion "$FLAGS" | while read -r line; do
    echo -e "$(echo "$line" | cut -d',' -f1),${LIGHT_GRAY}$(echo "$line" | cut -d',' -f2-)${NORMAL}"
  done
}

fn-help-subcommand-sanitize() {
  declare FUNC_FILE="$1" OUTGOING_FUNC_FILE="$2"
  local FUNCTION_FOUND=false
  local IFS OIFS

  touch "$OUTGOING_FUNC_FILE"

  OIFS="$IFS"
  IFS=,
  while read -r p; do
    IFS="$OIFS"
    if [[ "$p" == *"-cmd \"\$@\""* ]] || [[ "$p" == "" ]]; then
      continue
    fi

    if [[ "$FUNCTION_FOUND" == true ]]; then
      echo "$p" >>"$OUTGOING_FUNC_FILE"
      continue
    fi

    if [[ "$p" == *"()"* ]]; then
      FUNCTION_FOUND=true
      echo "$p" >>"$OUTGOING_FUNC_FILE"
      continue
    fi
  done <"$FUNC_FILE"
}

_fn-help-apply-shell-expansion() {
  declare desc="expand environment variables for a shell command"
  declare data="$1"
  declare delimiter="__apply_shell_expansion_delimiter__"
  declare command="cat <<$delimiter"$'\n'"$data"$'\n'"$delimiter"
  eval "$command"
}
