#!/bin/bash
# Purpose: display state of ngcpcfg setup and pending/recommended actions
################################################################################

set -e
set -u
set -o pipefail

# support testsuite
FUNCTIONS="${FUNCTIONS:-/usr/share/ngcp-ngcpcfg/functions/}"

if ! [ -r "${FUNCTIONS}"/main ] ; then
  printf "Error: %s/main could not be read. Exiting.\n" "${FUNCTIONS}">&2
  exit 1
fi

timestamp_replacementchars=''
# shellcheck disable=SC1090
. "${FUNCTIONS}"/main

# main script

if ! [ -d "${NGCPCTL_MAIN:-}" ] ; then
  log_error "Directory ${NGCPCTL_MAIN:-} does not exist yet. Execute 'ngcpcfg initialise'."
  exit 1
fi

usage() {
  printf "ngcpcfg status -- supported command line options:

--local-only - do not check state on any remote host(s) (HA/PRO only)\n\n"
}

# shellcheck disable=SC2034
{
# used on ngcpcfg-ha/functions/ha_features.execute_check_remote()
CHECK_REMOTE=true
REMOTE_INVOKED=false
while [ -n "${1:-}" ] ; do
  case "$1" in
    *--local-only*) CHECK_REMOTE=false ; shift ;;
    *--remote*)     REMOTE_INVOKED=true ; shift ;; # used when invoking ngcpcfg status remotely
    *--help*)   usage ; exit 0 ;;
    *) break ;;
  esac
done
}

check_local_state() {
  log_debug "check_local_state"

  log_debug "cd $NGCPCTL_MAIN"
  cd "$NGCPCTL_MAIN"

  log_info "Checking state of ${NGCPCFG_NAME:-ngcpcfg}:"

  if ! [ -r "${NGCPCTL_MAIN}/.git/HEAD" ] ; then
    log_warn "ngcpcfg has not been initialised yet. Execute 'ngcpcfg initialise'."
    exit 0
  fi

  log_info "OK:   has been initialised already"

  if check_maintenance_mode ; then
    log_info "Maintenance mode is enabled, skipping local state check for pending build/commit"
    return 0
  fi

  log_info "Checking state of configuration files:"
  if is_git_clean ; then
    log_info "OK:   nothing to commit"
  else
    if git diff-index --name-only HEAD | grep -q . ; then
      log_info "ACTION_NEEDED: configuration files have been modified:"
      log_debug "git diff-index --name-only HEAD | sed \"s;^;${NGCPCTL_MAIN}/;\""
      git diff-index --name-only HEAD | sed "s;^;${NGCPCTL_MAIN}/;" | sed "s/^/$timestamp_replacementchars/"
    fi

    if git ls-files --other --exclude-standard | grep -q . ; then
      log_info "ACTION_NEEDED: configuration files have been added:"
      log_debug "git ls-files --other --exclude-standard | sed \"s;^;${NGCPCTL_MAIN}/;\""
      git ls-files --other --exclude-standard | sed "s;^;${NGCPCTL_MAIN}/;" | sed "s/^/$timestamp_replacementchars/"
    fi

    log_info "-> execute 'ngcpcfg build' and 'ngcpcfg commit'"
  fi
}

check_etc_state() {
  log_debug "check_etc_state"

  log_debug "cd ${NGCPCTL_BASE}"
  cd "${NGCPCTL_BASE}"

  log_info "Checking state of ${NGCPCTL_BASE} files:"
  if is_git_clean ; then
    log_info "OK:   nothing to commit"
  else
    log_info "ACTION_NEEDED: configuration files changed (execute 'etckeeper commit [message]')"
  fi
}

check_branch() {
  log_info "Checking currently active branch:"

  local current_branch
  current_branch=$(compare_active_branch 'master')
  if [ "$current_branch" = 'master' ] ; then
    log_info "OK:   branch master active"
  else
    log_info "ACTION_NEEDED: branch '$current_branch' active - please switch to branch 'master'"
  fi
}

check_push() {
  if type -p execute_check_shared_storage &>/dev/null ; then
    log_debug "execute_check_shared_storage function, action 'push'"
    execute_check_shared_storage push
  fi
}

check_shared_storage() {
  if type -p execute_check_shared_storage &>/dev/null ; then
    log_debug "execute_check_shared_storage function, action all"
    execute_check_shared_storage all
  fi
}

check_remote() {
  if type -p execute_check_remote &>/dev/null ; then
    log_debug "execute_check_remote function"
    execute_check_remote "$@"
  fi
}


check_reboot_requests() {
  log_debug "check_requested_reboot"

  log_info "Checking for pending reboot requests:"

  if [ -f "${RUN_DIR}/reboot-required" ]; then
    log_info "ACTION_NEEDED: configuration, service or system changes requested a reboot"
    log_info "-> reboot the system at your earliest convenience"
  else
    log_info "OK:     no reboot requested"
  fi
}

check_pending_build() {
  log_debug "${FUNCNAME[@]}"

  log_debug "cd $NGCPCTL_MAIN"
  cd "$NGCPCTL_MAIN"

  if check_maintenance_mode ; then
    log_info "Maintenance mode is enabled, skipping check for pending build/apply"
    return 0
  fi

  log_info "Checking state of pending builds:"

  local latest_commit
  latest_commit=$(git log -1 --format="%H")
  log_debug "latest_commit = $latest_commit"

  if ! [ -f "${STATE_FILES_DIR}/build" ] ; then
    log_debug "File ${STATE_FILES_DIR}/build doesn't exist."
    log_info  "OK:       no build/apply executed yet, nothing to do"
    return 0
  fi

  local latest_build_commit
  latest_build_commit=$(cat "${STATE_FILES_DIR}/build")
  log_debug "latest_build_commit = $latest_build_commit"

  if [ -n "$latest_commit" ] && [ -n "$latest_build_commit" ] ; then
    if [ "$latest_build_commit" = "dirty" ] ; then
      log_info "OK:     nothing to build (latest build newer than latest commit)"
    elif [ "$latest_commit" = "$latest_build_commit" ] ; then
      log_info "OK:     nothing to build"
    else
      log_info "ACTION_NEEDED: commits without according build identified"
      log_info "-> execute either 'ngcpcfg build' or 'ngcpcfg apply'"
    fi
  fi
}

if [ -z "${1:-}" ] ; then
  check_local_state
  check_branch
  check_push
  check_etc_state
  check_pending_build
  check_shared_storage
  check_reboot_requests
fi

check_remote "$@"

## END OF FILE #################################################################