#!/usr/bin/bash
#
# Discovery Installer
#
export VERBOSE="n"
INSTALLER_COMMAND="discovery-installer"
QUIPUCORDS_PKG_ROOT="${QUIPUCORDS_PKG_ROOT:-/usr/share/${INSTALLER_COMMAND}}"
QUIPUCORDS_BIN_DIR=${QUIPUCORDS_PKG_ROOT}/bin

CONFIG_PATH="${QUIPUCORDS_PKG_ROOT}/config"
ENV_PATH="${QUIPUCORDS_PKG_ROOT}/env"

QUIPUCORDS_USER_PATH="${HOME}/.local/share/discovery"
ENV_USER_PATH="${HOME}/.config/discovery/env/"
SYSTEMD_USER_PATH="${HOME}/.config/containers/systemd/"

if [ "${1}" == "-v" ] || [ "${1}" == "--verbose" ]; then
  VERBOSE="y"
  shift
fi

COMMAND="${1}"
shift

function debug_msg {
  if [ "${VERBOSE}" == "y" ]; then
    echo "$@"
  fi
}

export OVERRIDE_CONF_DIR="" # Optional --override-conf-dir configuration directory

if [ "$(id -u)" -eq 0 ]; then
  echo "${INSTALLER_COMMAND} must not run as root."
  exit 1
fi

if [ -z "${XDG_RUNTIME_DIR}" ]; then
  export XDG_RUNTIME_DIR=/run/user/$UID
fi

if [ "${COMMAND}" == "create-server-password" ]; then
  "${QUIPUCORDS_BIN_DIR}"/create-server-password
  exit $?
fi

if [ "${COMMAND}" == "create-app-secret" ]; then
  "${QUIPUCORDS_BIN_DIR}"/create-app-secret
  exit $?
fi

function get_section {
  config_file="${1}"
  section_name="${2}"
  <"${config_file}" sed "0,/^\[${section_name}\]/d" | sed '/^[\b]*$/,$d'
}

function override_unit_section {
  export config_section="${1}"
  export override_section="${2}"
  if [ -z "${override_section}" ]; then
    echo "${config_section}"
    return
  fi
  updated_config="${config_section}"
  updated_config=$(
    echo "${override_section}" | cut -f1 -d= | sort -u |
      (
        while read -r var_name; do
          NL=$'\n'
          # number of var_name entries in the config section we want to update
          num_var_names=$(echo "${updated_config}" | grep -c "^${var_name}=" >/dev/null)
          var_lines=$(
            echo "${override_section}" | grep "^${var_name}=.*" |
              (
                var_lines=""
                while read -r line; do
                  if [ -z "${var_lines}" ]; then
                    var_lines="${line}"
                  else
                    var_lines="${var_lines}${NL}${line}"
                  fi
                done
                echo "${var_lines}"
              )
          )
          if [ "${num_var_names}" == "0" ]; then # just append the overrides at the end
            for line in ${var_lines}; do
              updated_config="${updated_config}${NL}${line}"
            done
          else # replace block
            # prefix is the config section that precedes the var_name entries
            prefix=$(echo "${updated_config}" | sed "/^${var_name}=.*/,$ d")
            # suffix is the config section that succeeds the var_name entries
            suffix=$(echo "${updated_config}" | sed "1,/^${var_name}=.*/d")
            suffix=$(echo "${suffix}" | sed "/^${var_name}=.*/d")
            updated_config="${prefix}"
            for line in ${var_lines}; do
              updated_config="${updated_config}${NL}${line}"
            done
            updated_config="${updated_config}${NL}${suffix}"
          fi
        done
        echo "${updated_config}"
      )
  )
  echo "${updated_config}"
}

function copy_container {
  container_config="${1}"
  target_dir="${2}"
  container_file=$(basename "${container_config}")
  debug_msg "Copying ${container_config} ${target_dir} ..."
  if [ -n "${OVERRIDE_CONF_DIR}" ] && [ -s "${OVERRIDE_CONF_DIR}/${container_file}" ]; then
    debug_msg "Overriding ${container_file}:"
    container_override="${OVERRIDE_CONF_DIR}/${container_file}"

    config_unit=$(get_section "${container_config}" "Unit")
    override_unit=$(get_section "${container_override}" "Unit")
    updated_unit=$(override_unit_section "${config_unit}" "${override_unit}")

    config_container=$(get_section "${container_config}" "Container")
    override_container=$(get_section "${container_override}" "Container")
    updated_container=$(override_unit_section "${config_container}" "${override_container}")

    config_service=$(get_section "${container_config}" "Service")
    override_service=$(get_section "${container_override}" "Service")
    updated_service=$(override_unit_section "${config_service}" "${override_service}")

    config_install=$(get_section "${container_config}" "Install")
    override_install=$(get_section "${container_override}" "Install")
    updated_install=$(override_unit_section "${config_install}" "${override_install}")

    NL=$'\n'
    updated_config="[Unit]${NL}${updated_unit}${NL}"
    updated_config="${updated_config}${NL}[Container]${NL}${updated_container}${NL}"
    updated_config="${updated_config}${NL}[Service]${NL}${updated_service}${NL}"
    updated_config="${updated_config}${NL}[Install]${NL}${updated_install}"
    echo "${updated_config}" >"${target_dir}/${container_file}"
    if [ "${VERBOSE}" = "y" ]; then
      diff --suppress-common-line -y "${container_config}" "${target_dir}/${container_file}"
      echo
    fi
  else
    cp "${container_config}" "${target_dir}/${container_file}"
  fi
}

function copy_env {
  env_config="${1}"
  target_dir="${2}"
  env_file=$(basename "${env_config}")
  env_unit="$(cat "${env_config}")"
  debug_msg "Copying ${env_config} ${target_dir} ..."
  if [ -n "${OVERRIDE_CONF_DIR}" ] && [ -s "${OVERRIDE_CONF_DIR}/${env_file}" ]; then
    debug_msg "Overriding ${env_file}:"
    while IFS=$'\n' read -r line; do
      env_var=${line%=*}
      env_val=${line#*=}
      if ! echo "${env_unit}" | grep "^${env_var}=" >/dev/null; then
        env_unit="${env_unit//${env_var}=.*/${env_var}=${env_val}/}"
      else
        NL=$'\n'
        env_unit="${env_unit}${NL}${env_var}=${env_val}"
      fi
    done <"${OVERRIDE_CONF_DIR}/${env_file}"
    echo "${env_unit}" >"${target_dir}/${env_file}"

    if [ "${VERBOSE}" = "y" ]; then
      diff --suppress-common-line -y "${env_config}" "${target_dir}/${env_file}"
      echo
    fi
  else
    echo "${env_unit}" >"${target_dir}/${env_file}"
  fi
}

if [ "${COMMAND}" == "install" ]; then
  if ! podman secret exists discovery-server-password; then
    "${QUIPUCORDS_BIN_DIR}"/create-server-password || exit 1
  fi

  if ! podman secret exists discovery-django-secret-key; then
    "${QUIPUCORDS_BIN_DIR}"/create-app-secret -y || exit 1
  fi

  if [ "${1}" == "--override-conf-dir" ]; then
    OVERRIDE_CONF_DIR="${2}"
    shift 2
    [[ -z "${OVERRIDE_CONF_DIR}" ]] && echo "Missing override configuration directory." && exit 1
    [[ ! -d "${OVERRIDE_CONF_DIR}" ]] && echo "Override configuration directory ${OVERRIDE_CONF_DIR} does not exist." && exit 1
  fi

  mkdir -p "${QUIPUCORDS_USER_PATH}/data"
  mkdir -p "${QUIPUCORDS_USER_PATH}/db"
  mkdir -p "${QUIPUCORDS_USER_PATH}/log"
  mkdir -p "${QUIPUCORDS_USER_PATH}/sshkeys"
  mkdir -p "${QUIPUCORDS_USER_PATH}/certs"

  systemctl --user reset-failed

  echo "Installing Discovery configuration files ..."
  mkdir -p "${ENV_USER_PATH}"
  mkdir -p "${SYSTEMD_USER_PATH}"

  cp "${CONFIG_PATH}"/*.network "${SYSTEMD_USER_PATH}"
  for container_file in "${CONFIG_PATH}"/*.container; do
    copy_container "${container_file}" "${SYSTEMD_USER_PATH}"
  done
  for env_file in "${ENV_PATH}"/*.env; do
    copy_env "${env_file}" "${ENV_USER_PATH}"
  done

  echo "Generate the Discovery services ..."
  systemctl --user daemon-reload

  echo "Discovery Installed."
  exit 0
fi

if [ "${COMMAND}" == "uninstall" ]; then

  echo "Stopping Discovery ..."
  systemctl --user stop discovery-app
  systemctl --user stop discovery-network

  echo "Removing Discovery Services ..."
  rm -f "${XDG_RUNTIME_DIR}"/systemd/generator/discovery-*.service
  rm -f "${SYSTEMD_USER_PATH}"/discovery*.network
  rm -f "${SYSTEMD_USER_PATH}"/discovery*.container
  rm -f "${ENV_USER_PATH}"/*.env

  systemctl --user daemon-reload
  systemctl --user reset-failed

  echo "Removing Discovery Data ..."
  rm -rf "${QUIPUCORDS_USER_PATH}/data"
  rm -rf "${QUIPUCORDS_USER_PATH}/log"
  rm -rf "${QUIPUCORDS_USER_PATH}/sshkeys"
  rm -rf "${QUIPUCORDS_USER_PATH}/certs"
  podman secret rm discovery-server-password &>/dev/null
  podman secret rm discovery-django-secret-key &>/dev/null

  echo "Discovery Uninstalled."
  exit 0
fi

echo "Usage: ${INSTALLER_COMMAND} [-v | --verbose] <command>"
echo ""
echo "Where <command> is one of:"
echo "  install                  - Install Discovery"
echo "  uninstall                - Uninstall Discovery"
echo "  create-server-password   - Create a Discovery server password"
echo "  create-app-secret        - Create a Discovery application secret"

exit 1
