#!/usr/bin/bash
set -euC

# GLOBALS
DATE_FORMAT="+%Y%m%d%H%M%S"

FORCE_OVERWRITE=${UCIDM_RESTORE_FORCE_OVERWRITE:-"false"}
DEBUG=${UCIDM_RESTORE_DEBUG:-"false"}
if [[ "${DEBUG}" == "true" ]]; then
    set -x
fi

UCIDM_HOME="${UCIDM_HOME:-"/var/opt/osstech/lib/ucidm"}"
COMPOSE_YML="compose.yml"
DOCKER_COMPOSE_COMMON_OPT=(--file "${UCIDM_HOME}/${COMPOSE_YML}")
DOCKER_COMPOSE="docker compose ${DOCKER_COMPOSE_COMMON_OPT[*]}"
MQADMIN="${MQADMIN:-"/opt/osstech/bin/mqadmin"}"
DEPLOY="${DEPLOY:-"/opt/osstech/bin/deploy"}"

COMPOSE_SERVICE_NAME_API="${COMPOSE_SERVICE_NAME_RABBITMQ:-"api"}"
COMPOSE_SERVICE_NAME_MONGO="${COMPOSE_SERVICE_NAME_MONGO:-"mongo"}"
COMPOSE_SERVICE_NAME_RABBITMQ="${COMPOSE_SERVICE_NAME_RABBITMQ:-"rabbitmq"}"

BACKUP_FILE_GLOB="ucidm-backup-*"
BACKUP_FILE_GLOB_MONGODB="mongodb-*.dump"
BACKUP_FILE_GLOB_RABBITMQ="rabbitmq-*.json"
BACKUP_FILE_GLOB_COMPOSE_DIR="composedir-*.tar"
BACKUP_FILE_GLOB_REVISION="revision-*.txt"

TMP_DIR=$(mktemp -d)

trap cleanup EXIT SIGINT SIGQUIT SIGTERM

cleanup() {
    rm -rf "${TMP_DIR}"
}

usage_exit() {
    echo "Usage: $0 BACKUP_FILE"
    exit 1
}

unarchive_backup_file() {
    local backup_file="${1}"
    rootlesskit tar --same-owner --same-permissions -C "${TMP_DIR}" -xf "${backup_file}" || return $?
}

init_directory() {
    local check_exists=(
    "compose.yml"
    ".env"
    "ucidm.env"
    "mongodb"
    "rabbitmq"
    "rabbitmq-data"
    )
    local check_result="true"

    if [[ -e "${UCIDM_HOME}/${COMPOSE_YML}" ]]; then
        ${DOCKER_COMPOSE} down \
        "${COMPOSE_SERVICE_NAME_API}" \
        "${COMPOSE_SERVICE_NAME_MONGO}" \
        "${COMPOSE_SERVICE_NAME_RABBITMQ}"
    fi

    echo "Check old file exists."

    for check_exist in "${check_exists[@]}"; do
        local check_exist_path="${UCIDM_HOME}/${check_exist}"
        if [[ -f ${check_exist_path} ]]; then
            echo "${check_exist_path} is exist"
            if [[ ${FORCE_OVERWRITE} == "true" ]]; then
                echo "Force Option True: remove --force ${check_exist_path}"
                rm -rf "${check_exist_path}"
            else
                check_result="false"
            fi
        fi
    done

    if [[ "${check_result}" == "false" ]]; then
        echo "Old file exists!" >&2
        return 1
    fi
}

restore_mongodb() {
    local mongo_backup_file \
        mongo_user \
        mongo_password \
        mongo_port \
        mongo_uri \
        mongo_db="ucidm" \
        mongo_tmp_config="/tmp/mongodb.conf"
    mongo_backup_file=$(find . -type f -name "${BACKUP_FILE_GLOB_MONGODB}*")
    mongo_user="$(${DOCKER_COMPOSE} exec -T "${COMPOSE_SERVICE_NAME_MONGO}" printenv MONGODB_ROOT_USER)"
    mongo_password="$(${DOCKER_COMPOSE} exec -T "${COMPOSE_SERVICE_NAME_MONGO}" printenv MONGODB_ROOT_PASSWORD)"
    mongo_port="$(${DOCKER_COMPOSE} exec -T "${COMPOSE_SERVICE_NAME_MONGO}" printenv MONGODB_PORT_NUMBER)"
    mongo_uri="mongodb://${mongo_user}@localhost:${mongo_port}"

    ${DOCKER_COMPOSE} exec -T "${COMPOSE_SERVICE_NAME_MONGO}" \
    bash -c "umask 0277; cat > \"${mongo_tmp_config}\"" <<EOF
password: ${mongo_password}
uri: ${mongo_uri}
EOF

    ${DOCKER_COMPOSE} exec -T "${COMPOSE_SERVICE_NAME_MONGO}" \
    mongorestore \
        --config "${mongo_tmp_config}" \
        --authenticationDatabase admin \
        --db "${mongo_db}" \
        --compressors=zstd \
        --archive < "${mongo_backup_file}"
    local rc=$?
    ${DOCKER_COMPOSE} exec -T "${COMPOSE_SERVICE_NAME_MONGO}" \
    rm -f ${mongo_tmp_config}
    return $rc
}

restore_rabbitmq() {
    local rabbitmq_backup_file mq_user mq_password
    rabbitmq_backup_file=$(find . -type f -name "${BACKUP_FILE_GLOB_RABBITMQ}*")
    mq_user=$(${DOCKER_COMPOSE} exec -T rabbitmq printenv RABBITMQ_DEFAULT_USER)
    mq_password=$(${DOCKER_COMPOSE} exec -T rabbitmq printenv RABBITMQ_DEFAULT_PASS)
    export RABBITMQ_USER="${mq_user}"
    export RABBITMQ_PASSWORD="${mq_password}" 
    export RABBITMQ_HOST="localhost:5672"
    ${MQADMIN} import -path "${rabbitmq_backup_file}" || return $?
}

restore_compose() {
    local compose_backup_file
    compose_backup_file=$(find . -type f -name "${BACKUP_FILE_GLOB_COMPOSE_DIR}")

    rootlesskit tar --same-owner --same-permissions -C "${UCIDM_HOME}" -xf "${compose_backup_file}" || return $?

    local mongo_data_dir="${UCIDM_HOME}/mongodb"
    if [[ ! -d "${mongo_data_dir}" ]]; then
        rootlesskit install -d -o 1001 -g root -m 0750 "${mongo_data_dir}"
    fi
}

restore_revision() {
    local revision_file
    revision_file=$(find . -type f -name "${BACKUP_FILE_GLOB_REVISION}")
    while read -r image_url revision; do
        # image_url = docker.io/osstech/ucidm-api:latest
        # image_url_remove_tag = docker.io/osstech/ucidm-api
        # image_name = osstech/ucidm-api:latest
        # image_name_remove_tag = osstech/ucidm-api
        if [[ "${revision}" == "" ]]; then
            echo "revision not found [${image_url} ${revision}]" 1>&2
            exit 1
        fi
        image_url_remove_tag="${image_url%:*}"
        image_name="${image_url#docker.io/}"
        image_name_remove_tag="${image_name%:*}"
        current_image=$(docker image ls --format '{{.Repository}}' "${image_name}")
        if [[ "${current_image}" == "${image_name_remove_tag}" ]]; then
            current_revision=$(docker image inspect --format '{{.Config.Labels.revision}}' "${image_name}")
            if [[ "${current_revision}" == "${revision}" ]]; then
                echo "[${image_url} ${revision}] container image already downloaded"
                continue
            fi
        fi
        echo "[${image_url} ${revision}] download container image"
        "${DEPLOY}" upgrade -path "${UCIDM_HOME}/${COMPOSE_YML}" -image "${image_url_remove_tag}:${revision}" || return $?
    done < "${revision_file}"
}

main() {
    if [[ $# -lt 1 ]]; then
        usage_exit
    fi
    local backup_file="${1}"
    if [[ ! -f ${backup_file} ]]; then
        echo "[${backup_file}] file not found" 1>&2
    fi

    init_directory || return $?

    unarchive_backup_file "${backup_file}" || return $?

    local unarchive_dir
    unarchive_dir="$(find "${TMP_DIR}" -type d -name "${BACKUP_FILE_GLOB}")"
    pushd "${unarchive_dir}"

    echo "restore compose at $(date ${DATE_FORMAT})"
    restore_compose || return $?

    echo "restore revision at $(date ${DATE_FORMAT})"
    restore_revision || return $?

    ${DOCKER_COMPOSE} up --wait \
        "${COMPOSE_SERVICE_NAME_MONGO}" \
        "${COMPOSE_SERVICE_NAME_RABBITMQ}"

    echo "restore mongodb at $(date ${DATE_FORMAT})"
    restore_mongodb || return $?

    echo "restore rabbitmq at $(date ${DATE_FORMAT})"
    restore_rabbitmq || return $?

    echo "done restore at $(date ${DATE_FORMAT})"
    popd
    return 0
}

main "$@" || exit $?
