#!/bin/bash
## compose: no-hooks

if [ -z "$SERVICE_DATASTORE" ]; then
    echo "This script is meant to be run through 'compose' to work properly." >&2
    exit 1
fi


version=0.1
usage="$exname [-h|--help] [--force|-f] [DBNAME]"
help="
USAGE:

$usage

DESCRIPTION:

Read stdin and send it to the restore API of odoo service to restore
in the database DBNAME. If DBNAME is not provided, it'll take the
default odoo database from the ${DARKCYAN}postgres-database${NORMAL} relation of
current service.

EXAMPLES:

  $exname < dump.zip
  $exname odoo2 < odoo2.zip

"


dbname=
neutralize=
while [ "$1" ]; do
    case "$1" in
        "--help"|"-h")
            print_help >&2
            exit 0
            ;;
        "--neutralize"|"-n")
            neutralize=yes
            ;;
        "--force"|"-f")
            force=yes
            ;;
        --*|-*)
            err "Unexpected optional argument '$1'"
            print_usage >&2
            exit 1
            ;;
        *)
            [ -z "$dbname" ] && { dbname=$1 ; shift ; continue ; }
            err "Unexpected positional argument '$1'"
            print_usage >&2
            exit 1
        ;;
    esac
    shift
done


version:ge() { [ "$(printf '%s\n' "$@" | sort -rV | head -n 1)" == "$1" ]; }
version:lt() { ! version:ge "$@"; }


if [ -z "$dbname" ]; then

    ##
    ## Fetch default dbname in relation to postgres-database
    ##

    ## XXXvlab: can't get real config here
    if ! read-0 ts _ _ < <(get_service_relation "$SERVICE_NAME" "postgres-database"); then
        err "Couldn't find relation ${DARKCYAN}postgres-database${NORMAL}."
        exit 1
    fi

    relation_file=$(get_relation_data_dir "$SERVICE_NAME" "$ts" "postgres-database") || {
        err "Failed to find relation file"
        exit 1
    }

    postgres_config=$(cat "$relation_file"/data) || exit 2

    dbname="$(e "$postgres_config" | shyaml get-value dbname)" || {
        err "Couldn't retrieve information of ${DARKCYAN}postgres-database${NORMAL}'s relation."
        exit 1
    }
fi

set -e

curl_opts=()

## Ensure odoo is launched
service_def=$(get_compose_service_def "$SERVICE_NAME")

## XXXvlab: should be moved to lib
CONFIG=$SERVICE_CONFIGSTORE/etc/odoo-server.conf
ADMIN_PASSWORD=$(echo "$service_def" | shyaml -q get-value options.admin-password) || {
    if [ -e "$CONFIG" ]; then
        ADMIN_PASSWORD=$(grep ^admin_passwd "$CONFIG" | sed -r 's/^admin_passwd\s+=\s+(.+)$/\1/g')
    fi
    if [ -z "$ADMIN_PASSWORD" ]; then
        err "Could not find 'admin-password' in $SERVICE_NAME service definition nor in config file."
        exit 1
    fi
}

containers="$(get_running_containers_for_service "$SERVICE_NAME")"
if [ -z "$containers" ]; then
    err "No containers running for service $DARKYELLOW$SERVICE_NAME$NORMAL."
    exit 1
fi

if [ "$(echo "$containers" | wc -l)" -gt 1 ]; then
    err "More than 1 container running for service $DARKYELLOW$SERVICE_NAME$NORMAL."
    echo "  Please contact administrator to fix this issue." >&2
    exit 1
fi

container="$(echo "$containers" | head -n 1)"
odoo_version=$(docker exec "$container" python -c 'import odoo.release; print(odoo.release.version)') || {
    err "Failed to get odoo version."
    exit 1
}
if version:lt "$odoo_version" "16.0" && [ -n "$neutralize" ]; then
    err "Option \`\`--neutralize\`\` (or \`\`-n\`\`)" \
        "is only available for odoo ${WHITE}16.0${NORMAL}+."
    echo "   Service ${DARKYELLOW}$SERVICE_NAME${NORMAL} is running odoo ${WHITE}$odoo_version${NORMAL}" >&2
    exit 1
fi

if [ -n "$neutralize" ]; then
    curl_opts+=(-F "neutralize_database=true")
fi

container_network_ip=$(get_healthy_container_ip_for_service "$SERVICE_NAME" 8069 4) || {
    err "Please ensure that $DARKYELLOW$service$NORMAL is running before using '$exname'."
    exit 1
}

container_ip=${container_network_ip##*:}
container_network=${container_network_ip%%:*}


DEFAULT_CURL_IMAGE=${DEFAULT_CURL_IMAGE:-docker.0k.io/curl}

check_input() {
    local chars
    read -n 2 -r chars
    if [ "$chars" != "PK" ]; then
        err "Unexpected input not matching ZIP signature. Invalid dump."
        echo "  First chars: '$chars'"
        exit 1
    fi
    {
        printf "%s" "$chars"
        cat
    }
}

## Beware that we are not on the host, so we need to create the
## fifo in a place we can share with the curl container.
export TMPDIR=/var/cache/compose
settmpdir RESTORE_TMPDIR

mkfifo "$RESTORE_TMPDIR/fifo"

## Using fifo because if using ``@-`` curl will load all the database
## in memory before sending it, which is NOT desirable as the size of
## the database can be greater than available memory. Using fifo, we
## force the data to be streamed.
cmd=(
    docker run -i --rm --network "$container_network"
      -v "$RESTORE_TMPDIR/fifo:/tmp/restore/fifo"
        "$DEFAULT_CURL_IMAGE"
        -sS 
        -X POST 
        -F "master_pwd=${ADMIN_PASSWORD}" 
        -F "name=${dbname}"
        -F "backup_file=@/tmp/restore/fifo"
        http://${container_ip}:8069/web/database/restore
	)

## XXXvlab: contains password, left only for advanced debug
#echo "COMMAND: ${cmd[@]}" >&2

"${cmd[@]}" > "$RESTORE_TMPDIR/out" &
pid=$!
check_input > "$RESTORE_TMPDIR/fifo"
wait "$pid" || {
    die "Posting to odoo restore API through curl was unsuccessfull."
}

out=$(cat "$RESTORE_TMPDIR/out")

if [[ "$out" == *"<html>"* ]]; then
    errmsg=$(echo "$out" | grep "alert-danger")
    errmsg=${errmsg#*>}
    errmsg=${errmsg%%<*}
    if [ "$errmsg" ]; then
        errmsg=$(echo "$errmsg" | recode html..utf8)
        die "$errmsg"
    fi
    die "Unexpected output. Restore probably failed."
fi >&2

info "Restored stdin dump to odoo '$dbname'."