#!/usr/bin/bash
set -euC

# GLOBALS
DATE=$(date +%Y%m%d%H%M%S)
ucidm_backup_conf="${UCIDM_BACKUP_CONF:-"/opt/osstech/etc/ucidm/ucidm-backup.conf"}"
backup_dir="/opt/osstech/var/backup/ucidm"
backup_maxage="3"


if [[ -f "${ucidm_backup_conf}" ]]; then
    # shellcheck disable=SC1090
    . "${ucidm_backup_conf}"
fi

backup_dir="${UCIDM_BACKUP_DIR:-"${backup_dir}"}"
backup_maxage="${UCIDM_BACKUP_MAXAGE:-"${backup_maxage}"}"

BACKUP_PREFIX="ucidm-backup"
BACKUP_DIRNAME="${BACKUP_PREFIX}-${DATE}"
BACKUP_FILE="${backup_dir}/${BACKUP_DIRNAME}.tar.zst"
UCIDM_HOME="${UCIDM_HOME:-"/var/opt/osstech/lib/ucidm"}"
COMPOSE_YML="${UCIDM_HOME}/compose.yml"
COMPOSE_ENV_FILE="${UCIDM_HOME}/ucidm.env"
COMPOSE_CMD="${COMPOSE_CMD:-"docker compose"}"
MQADMIN="${MQADMIN:-"/opt/osstech/bin/mqadmin"}"
TMP_DIR=$(mktemp -d)
BACKUP_TMP_DIR="${TMP_DIR}/${BACKUP_DIRNAME}"

trap cleanup EXIT SIGINT SIGQUIT SIGTERM

remove_old_backup() {
    local backup_files=("${backup_dir}/${BACKUP_PREFIX}"*.tar.zst)
    local n=$((${#backup_files[@]} - backup_maxage))
    if [[ $n -le 0 ]]; then
        return 0
    fi
    for f in "${backup_files[@]::$n}"
    do
            echo "remove old backup: $f"
            rm -f "${f}"
    done
}

cleanup() {
    echo "clean up"
    rm -rf "${TMP_DIR}"
    remove_old_backup
}

init_directory() {
  mkdir -p "${BACKUP_TMP_DIR}/"
}

## mongodb
backup_mongodb() {
    local mongo_user \
        mongo_password \
        mongo_port \
        mongo_uri \
        mongo_db="ucidm"
    mongo_user="$(${COMPOSE_CMD} --file "${COMPOSE_YML}" --env-file "${COMPOSE_ENV_FILE}" exec -T mongo printenv MONGODB_ROOT_USER)"
    mongo_password="$(${COMPOSE_CMD} --file "${COMPOSE_YML}" --env-file "${COMPOSE_ENV_FILE}" exec -T mongo printenv MONGODB_ROOT_PASSWORD)"
    mongo_port="$(${COMPOSE_CMD} --file "${COMPOSE_YML}" --env-file "${COMPOSE_ENV_FILE}" exec -T mongo printenv MONGODB_PORT_NUMBER)"
    mongo_uri="mongodb://${mongo_user}@localhost:${mongo_port}"
    echo "${mongo_password}" | ${COMPOSE_CMD} --file "${COMPOSE_YML}" --env-file "${COMPOSE_ENV_FILE}" exec -T mongo mongodump --quiet --authenticationDatabase admin --uri "${mongo_uri}" --db "${mongo_db}" --compressors=zstd --archive > "${BACKUP_TMP_DIR}/mongodb-${DATE}.dump"
    return $?
}

## rabbitmq
backup_rabbitmq() {
    local mq_user \
        mq_password
    mq_user="$(${COMPOSE_CMD} --file "${COMPOSE_YML}" --env-file "${COMPOSE_ENV_FILE}" exec -T rabbitmq printenv RABBITMQ_DEFAULT_USER)"
    mq_password="$(${COMPOSE_CMD} --file "${COMPOSE_YML}" --env-file "${COMPOSE_ENV_FILE}" exec -T rabbitmq printenv RABBITMQ_DEFAULT_PASS)"
    export MQADMIN_PORT=15672
    export RABBITMQ_USER="${mq_user}"
    export RABBITMQ_PASSWORD="${mq_password}"
    export RABBITMQ_HOST="localhost:5672"
    "${MQADMIN}" export > "${BACKUP_TMP_DIR}/rabbitmq-${DATE}.json"
    return $?
}

## compose
backup_compose() {
    local execlude_dirs=(
      ".config"
      ".docker"
      ".lesshst"
      ".local"
      ".ssh"
      ".vim*"
      ".bash*"
      ".zsh*"
      ".profile*"
      "mongodb"
      "rabbitmq-data"
    )

    local excludes=()
    for dirname in "${execlude_dirs[@]}"
    do
        excludes+=(--exclude "${dirname}")
    done

    local compose_backup_file="${BACKUP_TMP_DIR}/composedir-${DATE}.tar"

    rootlesskit tar --same-owner --same-permissions -C "${UCIDM_HOME}" "${excludes[@]}" -cf "${compose_backup_file}" . || return $?
    return $?
}

## revision
backup_revision() {
    local revision_file images
    revision_file="${BACKUP_TMP_DIR}/revision-${DATE}.txt"
    mapfile -t images < <(${COMPOSE_CMD} --file "${COMPOSE_YML}" --env-file "${COMPOSE_ENV_FILE}" config --images | sort -u | grep "osstech")

    for image in "${images[@]}"; do
        revision=$(docker image inspect --format "{{.Config.Labels.revision}}" "${image}")
        echo "${image} ${revision}" >> "${revision_file}"
    done
}

## archive
archive() {
    rootlesskit tar --same-owner --same-permissions -C "${TMP_DIR}" --zstd -cf "${BACKUP_FILE}" "${BACKUP_DIRNAME}" || return $?
}

main() {

    init_directory || return $?

    echo "backup mongodb at $(date +%Y-%m-%dT%H:%M:%S)"
    backup_mongodb || return $?

    echo "backup rabbitmq at $(date +%Y-%m-%dT%H:%M:%S)"
    backup_rabbitmq || return $?

    echo "backup compose at $(date +%Y-%m-%dT%H:%M:%S)"
    backup_compose || return $?

    echo "backup revision at $(date +%Y-%m-%dT%H:%M:%S)"
    backup_revision || return $?

    echo "archive at $(date +%Y-%m-%dT%H:%M:%S)"
    archive || return $?

    echo "bcakup rotation at $(date +%Y-%m-%dT%H:%M:%S)"
    remove_old_backup || return $?

    echo "done backup at $(date +%Y-%m-%dT%H:%M:%S)"
    return 0

}

main "$@" || exit $?
