#!/bin/bash

set -e
set -u

declare -r c_me="$0"
db_config_file="${db_config_file:-/etc/ngcp-reset-db.conf}"
BACKUP="${BACKUP:-/ngcp-data/backup}"
NGCP_ROLES="${NGCP_ROLES:-/etc/default/ngcp-roles}"
NGCP_DB_SCHEMA="${NGCP_DB_SCHEMA:-/usr/share/ngcp-db-schema}"
backup=true
local_only=false
start_services=true
declare -a mysql_cmd=('mysql')
mysql_cmd+=(--defaults-extra-file='/etc/mysql/sipwise_extra.cnf')

# backwards compability
if [[ -n "${FORCE_RESET:-}" ]] ; then
  force_reset=true
else
  force_reset=false
fi

die() {
  echo "ERROR: $*" >&2
  exit 1
}

help() {
  echo "Usage: ${c_me} [OPTIONS]"
  echo
  echo "Wipe out all existing data"
  echo
  echo "  Supported options :"
  echo "     -h|--help        : show this help"
  echo "     -f|--force       : don't ask for confirmation"
  echo "     -l|--local-only  : don't try to connect to neighbours"
  echo "     -s|--skip-start  : don't start services after removal"
  echo "     -k|--skip-backup : don't create backups before removal"
}

configure() {
  IFS=" " read -r -a _list <<< "$1"
  local _opt_temp=
  local _cmdline_opts="help,force,local-only,skip-start,skip-backup"
  _opt_temp=$(getopt -n "${c_me}" -o "+hflks" -l "${_cmdline_opts}" -- "${_list[@]}")
  eval set -- "${_opt_temp}"

  while :; do
    case "$1" in
    --help|-h)
      help; exit 0
      ;;
    --force|-f)
      force_reset=true
      ;;
    --local-only|-l)
      local_only=true
      ;;
    --skip-start|-s)
      start_services=false
      ;;
    --skip-backup|-k)
      backup=false
      ;;
    --)
      shift; break
      ;;
    *)
      echo "Internal getopt error! $1" >&2
      exit 1
      ;;
    esac
    shift
  done
}

neighbours() {
  if [[ "${NGCP_TYPE:-}" == "sppro" || "${NGCP_TYPE:-}" == "carrier" ]]; then
    echo "Stopping services on the peer '${NGCP_PEERNAME}'..."
    ngcp-ssh "${NGCP_PEERNAME}" "ngcp-service --group ngcp-upgrade-essential --action stop" || true

    echo "Starting DB service on the peer '${NGCP_PEERNAME}'..."
    ngcp-ssh "${NGCP_PEERNAME}" "ngcp-service mysql start"

    echo "[PRO/Carrier] Initialising DB on peer '${NGCP_PEERNAME}' as a copy of localhost..."
    sync_db_cmd="/usr/sbin/ngcp-sync-db --force --verbose --ssh-tunnel=33125 --local-host=localhost --fix-db-schema --set-local-grants"
    if ! (ngcp-ssh "${NGCP_PEERNAME}" "${sync_db_cmd}") ; then
      die "[PRO/Carrier] Failed to run ngcp-sync-db on peer '${NGCP_PEERNAME}', aborting."
    fi

    echo "Starting services on the peer '${NGCP_PEERNAME}'..."
    ngcp-ssh "${NGCP_PEERNAME}" "ngcp-service --group ngcp-upgrade-essential --action start" || RC_peer=$?

    # Every time we reset DB host on Carrier installation,
    # we have to also reset every mariadb:3308 read-only copy on PRX and LB->LI nodes
    if [[ "${NGCP_TYPE:-}" == "carrier" && "${NGCP_IS_DB}" == "yes" ]]; then
      check_cmd="source /etc/default/ngcp-roles ; \
        if [[ \"\${NGCP_IS_PROXY}\" == \"yes\" || ( \"\${NGCP_IS_LB}\" == \"yes\" && \"\${NGCP_IS_LI}\" == \"yes\" ) ]]; then \
          exit 0 ; \
        else \
          exit 1 ; \
        fi"
      for host in ${NGCP_NEIGHBOURS}; do
        if ngcp-ssh "${host}" "${check_cmd}" ; then
          # We should perform migration mysql:3308 on Carrier hosts PROXY and LB (for LI case only)
          echo "[Carrier] Init DB:3308 on host '${host}' as a read-only copy of 'localhost:3306' ..."
          ngcp-ssh "${host}" "ngcp-sync-db --force --verbose --use-central-db --repl-mode master-slave"
        else
          echo "[Carrier] Skipping reset DB:3308 on host '${host}' (unnecessary here)."
        fi
      done
    fi
  fi
}

configure "$*"

if [ ! -f "${NGCP_ROLES}" ] ; then
  die "${NGCP_ROLES} does not exist or not a regular file"
fi
# shellcheck disable=SC1090,SC1091
source "${NGCP_ROLES}"

if [[ "${EUID}" != 0 ]] ; then
  die "This script requires root permissions."
fi

if "${force_reset}" ; then
  echo "Running in automated mode."
else
  echo -n "This will wipe out all existing data. Are you sure? (y/N) "
  read -r a
  case "${a,,}" in
    y|yes|Y)
      :
      ;;
    *)
      echo "Aborted as requested"
      exit 0
      ;;
  esac
  unset a
fi

if [[ ! -f "${db_config_file}" ]] ; then
  die "This script requires DB config file: ${db_config_file}"
else
  # shellcheck disable=SC1090,SC1091
  source "${db_config_file}"
fi

if ! "${backup}" ; then
  echo "Skipping backup process, as requested..."
else
  echo "Backup databases..."
  ngcp-service mysql start || true

  START_TIME=$(date +%Y%m%d_%H%M%S)
  touch           "${BACKUP}/db_backup.sql-${START_TIME}"
  chmod 600       "${BACKUP}/db_backup.sql-${START_TIME}"
  chown root:root "${BACKUP}/db_backup.sql-${START_TIME}"
  
  # back-up (most) DBs before reset
  for db in "${NGCP_DB_RESET_LIST[@]}"; do
    # do not back-up sipstats, large and unimportant
    if [[ "${db}" == "sipstats" ]]; then
      continue
    fi

    if ! mysqldump --defaults-extra-file='/etc/mysql/sipwise_extra.cnf' \
        --databases --add-drop-database \
        "${db}" >> "${BACKUP}/db_backup.sql-${START_TIME}" ; then
      die "Error backing up DB '${db}' to ${BACKUP}/db_backup.sql-${START_TIME}"
    fi
  done
fi

echo "Stopping services on the current node..."
ngcp-service --group ngcp-upgrade-essential --action stop || true

echo "Starting DB service on the current node..."
ngcp-service mysql start
echo "Dropping databases..."
for db in "${NGCP_DB_RESET_LIST[@]}"; do
  echo "Dropping databases '${db}' on localhost..."
  "${mysql_cmd[@]}" -e "SET FOREIGN_KEY_CHECKS=0; DROP DATABASE IF EXISTS ${db}"
done

echo "Initialising DB schema..."
# The order of schemes is important as there are sql dependencies
declare -a schemes=()
schemes+=("accounting")
schemes+=("ngcp")
schemes+=("provisioning")
schemes+=("billing")
schemes+=("carrier")
schemes+=("fileshare")
schemes+=("kamailio")
schemes+=("ldap")
schemes+=("prosody")
schemes+=("sipstats")
schemes+=("stats")
schemes+=("freeswitch")
echo "Creating schemes ${schemes[*]}"
for schema in "${schemes[@]}"; do
  sql_file="${NGCP_DB_SCHEMA}/schema/${schema}.sql"
  echo "Applying ${sql_file}"
  "${mysql_cmd[@]}" < "${sql_file}"
done
if [[ "${NGCP_TYPE:-}" == 'sppro' || "${NGCP_TYPE:-}" == 'carrier' ]]; then
  ngcp_nodename="$(ngcp-nodename)"
  "${mysql_cmd[@]}" ngcp -e "UPDATE db_schema SET node = '${ngcp_nodename}';"
fi

echo "Updating DB schema..."
if ! (AUTOMATED_INSTALL_MODE=1 ngcp-update-db-schema -f) ; then
  die "Failed to run ngcp-update-db-schema, aborting."
fi

if ${local_only} ; then
  echo "Skipping execution on neighbours, as requested..."
else
  neighbours
fi

echo "Initialising DB grants..."
if ! ngcp-sync-db-grants --recreate-user ; then
  die "Failed to run ngcp-sync-db-grants, aborting."
fi

echo "Initialising DB passwords..."
if ! ngcp-sync-db-creds -r ; then
  die "Failed to run ngcp-sync-db-creds, aborting."
fi

if ! ${start_services} ; then
  echo "Skipping start of services, as requested..."
else
  echo "Starting services..."
  ngcp-service --group ngcp-upgrade-essential --action start || RC_local=$?

  if [[ "${RC_local:-0}" != "0" && "${RC_peer:-0}" != "0" ]]; then
    die "There were some errors restoring services on the current node and on the peer '${NGCP_PEERNAME}'"
  elif [[ "${RC_peer:-0}" != "0" ]]; then
    die "There were some errors restoring services on the peer '${NGCP_PEERNAME}'"
  elif [[ "${RC_local:-0}" != "0" ]]; then
    die "There were some errors restoring services on the current node"
  fi
fi

echo "All databases have been re-created successfully"
exit 0
