#!/bin/sh

set -eu

BASE_URL=${PAPERDESK_UPDATE_BASE_URL:-http://192.168.1.40:8090}
STATE=${PAPERDESK_UPDATE_STATE:-/home/root/.local/share/paperdesk}
SETTINGS=${PAPERDESK_UPDATE_SETTINGS:-/home/root/.config/remarkable/xochitl.conf}
PUBLIC_KEY=${PAPERDESK_UPDATE_PUBLIC_KEY:-/home/root/.local/lib/paperdesk/release-public.pem}
WORK=${PAPERDESK_UPDATE_WORK:-$STATE/update-work}
LOCK=${PAPERDESK_UPDATE_LOCK:-/run/paperdesk-update.lock}
UNINSTALLER=${PAPERDESK_UNINSTALLER:-/home/root/.local/lib/paperdesk/paperdesk-uninstall}

read_setting() {
    awk -F= -v wanted="$1" '
        BEGIN { section=0 }
        /^\[PaperDeskUpdate\]$/ { section=1; next }
        /^\[/ { section=0 }
        section && $1 == wanted { sub(/^[^=]*=/, ""); print; exit }
    ' "$SETTINGS"
}

clear_request() {
    awk '
        BEGIN { section=0 }
        /^\[PaperDeskUpdate\]$/ { section=1; print; next }
        /^\[/ { section=0 }
        section && /^installRequested=/ { print "installRequested=false"; next }
        section && /^uninstallRequested=/ { print "uninstallRequested=false"; next }
        { print }
    ' "$SETTINGS" > "$SETTINGS.paperdesk-update"
    mv "$SETTINGS.paperdesk-update" "$SETTINGS"
}

write_status() {
    mkdir -p "$STATE"
    printf '{"state":"%s","message":"%s","version":"%s"}\n' "$1" "$2" "$3" > "$STATE/update-status.json.tmp"
    mv "$STATE/update-status.json.tmp" "$STATE/update-status.json"
}

version_is_newer() {
    awk -F. -v candidate="$1" -v installed="$2" 'BEGIN {
        split(candidate, a, "."); split(installed, b, ".")
        for (i=1; i<=3; ++i) {
            if ((a[i] + 0) > (b[i] + 0)) exit 0
            if ((a[i] + 0) < (b[i] + 0)) exit 1
        }
        exit 1
    }'
}

fail() {
    write_status "error" "$1" "${LATEST_VERSION:-}"
    exit 1
}

REQUESTED=$(read_setting installRequested || true)
UNINSTALL_REQUESTED=$(read_setting uninstallRequested || true)
[ "$REQUESTED" = "true" ] || [ "$UNINSTALL_REQUESTED" = "true" ] || exit 0
REQUESTED_VERSION=$(read_setting requestedVersion || true)
clear_request

exec 9>"$LOCK"
flock -n 9 || fail "Another update is already running"

if [ "$UNINSTALL_REQUESTED" = "true" ]; then
    write_status "uninstalling" "Removing PaperDesk" ""
    [ -x "$UNINSTALLER" ] || fail "The PaperDesk uninstaller is unavailable"
    "$UNINSTALLER" --from-care >/tmp/paperdesk-uninstall.log 2>&1 || fail "PaperDesk could not be removed"
    write_status "success" "PaperDesk removed" ""
    /home/root/xovi/start >/tmp/paperdesk-uninstall-reload.log 2>&1 || true
    exit 0
fi

rm -rf "$WORK"
mkdir -p "$WORK"
trap 'rm -rf "$WORK"' EXIT INT TERM
write_status "checking" "Verifying the official release" "$REQUESTED_VERSION"

wget -q -T 25 -O "$WORK/latest.json" "$BASE_URL/update/latest.json" || fail "Could not download release information"
wget -q -T 25 -O "$WORK/latest.json.sig" "$BASE_URL/update/latest.json.sig" || fail "Could not download release signature"
openssl pkeyutl -verify -rawin -pubin -inkey "$PUBLIC_KEY" -sigfile "$WORK/latest.json.sig" -in "$WORK/latest.json" >/dev/null 2>&1 || fail "Release signature is invalid"

LATEST_VERSION=$(sed -n 's/^[[:space:]]*"version": "\([0-9][0-9.]*\)",*$/\1/p' "$WORK/latest.json")
ARCHIVE_URL=$(sed -n 's/^[[:space:]]*"archiveUrl": "\([^" ]*\)",*$/\1/p' "$WORK/latest.json")
ARCHIVE_SHA=$(sed -n 's/^[[:space:]]*"archiveSha256": "\([0-9a-f]*\)",*$/\1/p' "$WORK/latest.json")
ARCHIVE_SIZE=$(sed -n 's/^[[:space:]]*"archiveSize": \([0-9]*\),*$/\1/p' "$WORK/latest.json")

printf '%s' "$LATEST_VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' || fail "Release version is invalid"
printf '%s' "$ARCHIVE_URL" | grep -Eq '^/download/paperdesk-[0-9]+\.[0-9]+\.[0-9]+\.zip$' || fail "Release download path is invalid"
printf '%s' "$ARCHIVE_SHA" | grep -Eq '^[0-9a-f]{64}$' || fail "Release checksum is invalid"
printf '%s' "$ARCHIVE_SIZE" | grep -Eq '^[0-9]+$' || fail "Release size is invalid"
[ "$ARCHIVE_SIZE" -gt 0 ] && [ "$ARCHIVE_SIZE" -le 52428800 ] || fail "Release size is outside the safe limit"
[ "$LATEST_VERSION" = "$REQUESTED_VERSION" ] || fail "The available release changed; check again"

CURRENT=$(tr -d '\r\n' < "$STATE/current-version" 2>/dev/null || printf '0.0.0')
if ! version_is_newer "$LATEST_VERSION" "$CURRENT"; then
    write_status "current" "PaperDesk is already up to date" "$LATEST_VERSION"
    exit 0
fi

write_status "downloading" "Downloading PaperDesk $LATEST_VERSION" "$LATEST_VERSION"
wget -q -T 90 -O "$WORK/paperdesk.zip.partial" "$BASE_URL$ARCHIVE_URL" || fail "The update download failed"
[ "$(wc -c < "$WORK/paperdesk.zip.partial" | tr -d ' ')" = "$ARCHIVE_SIZE" ] || fail "The update size does not match"
printf '%s  %s\n' "$ARCHIVE_SHA" "$WORK/paperdesk.zip.partial" | sha256sum -c - >/dev/null 2>&1 || fail "The update checksum does not match"
mv "$WORK/paperdesk.zip.partial" "$WORK/paperdesk.zip"

write_status "installing" "Installing PaperDesk $LATEST_VERSION" "$LATEST_VERSION"
unzip -q "$WORK/paperdesk.zip" -d "$WORK/unpacked" || fail "The update archive could not be opened"
RELEASE_DIR="$WORK/unpacked/paperdesk-$LATEST_VERSION"
[ -f "$RELEASE_DIR/install.sh" ] && [ -f "$RELEASE_DIR/SHA256SUMS" ] || fail "The update package is incomplete"
(cd "$RELEASE_DIR" && sha256sum -c SHA256SUMS >/dev/null) || fail "Files inside the update package are invalid"
chmod 755 "$RELEASE_DIR/install.sh"
"$RELEASE_DIR/install.sh" --from-updater >/tmp/paperdesk-update-install.log 2>&1 || fail "Installation failed; the previous version is still available"

write_status "success" "PaperDesk $LATEST_VERSION installed" "$LATEST_VERSION"
systemctl --no-block restart xovi-autostart.service
