#!/bin/bash
# vega-execute-update — install a verified vega-software deb from the handoff dir.
#
# Started by dakupdate.service, which dakupdate.path triggers when a .deb lands
# in HANDOFF_DIR. The check scripts verified the package before staging it; it
# is verified again here, right before dpkg, and nothing is installed unless
# vega-verify-package passes.
set -euo pipefail

HANDOFF_DIR="/var/lib/vega/update"
VERIFY_CMD="/usr/bin/vega-verify-package"
INSTALL_COMPLETE_MARKER="/run/vega/update-just-installed"
EMIT_EVENT_CMD="/usr/share/vega/ui/update_scripts/vega-emit-update-event"

log() {
    echo "vega-execute-update: $*" | systemd-cat -t vega-execute-update -p "${LOG_PRIORITY:-info}"
}

emit_event() {
    local event_type="$1"
    local reason="${2:-}"
    if [ -x "$EMIT_EVENT_CMD" ]; then
        "$EMIT_EVENT_CMD" --type "$event_type" ${reason:+--reason "$reason"} 2>/dev/null || true
    fi
}

# Empty the handoff dir on every exit, success or failure. dakupdate.path starts
# this service whenever a .deb is present, so a rejected or failed package left
# behind would be retried forever (dakupdate.service disables the start limit).
# A power cut skips this trap, which is what lets an interrupted install resume
# on the next boot.
trap 'rm -f "$HANDOFF_DIR"/* 2>/dev/null || true' EXIT

log "starting install from $HANDOFF_DIR"

# ── Find the .deb ─────────────────────────────────────────────────────────────
DEB_COUNT=$(ls "$HANDOFF_DIR"/*.deb 2>/dev/null | wc -l)

if [ "$DEB_COUNT" = "0" ]; then
    LOG_PRIORITY=err log "No .deb file found in $HANDOFF_DIR"
    exit 1
fi

if [ "$DEB_COUNT" -gt "1" ]; then
    LOG_PRIORITY=err log "ERROR: $DEB_COUNT .deb files in $HANDOFF_DIR (expected 1). Aborting."
    exit 1
fi

DEB_FILE=$(ls "$HANDOFF_DIR"/*.deb)
log "Found package: $DEB_FILE"

# ── Verification gate ─────────────────────────────────────────────────────────
log "Running verification: $DEB_FILE"
VERIFY_RC=0
"$VERIFY_CMD" "$DEB_FILE" || VERIFY_RC=$?
if [ "$VERIFY_RC" != "0" ]; then
    case "$VERIFY_RC" in
        1) LOG_PRIORITY=err log "ABORT: Package structurally corrupt. Not installing." ;;
        2) LOG_PRIORITY=err log "ABORT: SHA256 checksum failure. Not installing." ;;
        3) LOG_PRIORITY=err log "ABORT: Signature invalid. Not installing." ;;
        *) LOG_PRIORITY=err log "ABORT: Verification failed (exit $VERIFY_RC). Not installing." ;;
    esac
    exit "$VERIFY_RC"
fi
log "Verification passed."

# ── Wait for dpkg lock (up to 60s) ────────────────────────────────────────────
LOCK_WAIT=0
while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do
    if [ "$LOCK_WAIT" -ge 60 ]; then
        LOG_PRIORITY=err log "FAIL: dpkg lock held for 60s — aborting."
        exit 2
    fi
    log "Waiting for dpkg lock... (${LOCK_WAIT}s)"
    sleep 2
    LOCK_WAIT=$((LOCK_WAIT + 2))
done

# ── Install ───────────────────────────────────────────────────────────────────
emit_event "update-installing"
log "running dpkg -i $DEB_FILE"
INSTALL_RC=0
dpkg -i "$DEB_FILE" || INSTALL_RC=$?

if [ "$INSTALL_RC" != "0" ]; then
    LOG_PRIORITY=err log "FAIL: dpkg -i returned exit $INSTALL_RC for $DEB_FILE"
    exit "$INSTALL_RC"
fi

# Write the success marker so server.js can broadcast "update-complete" to the first reconnecting WebSocket client.
echo "$DEB_FILE" > "$INSTALL_COMPLETE_MARKER"
log "install complete"
