#!/bin/bash
# usb-helper.sh — worker for the standalone FreezeOS USB creator.
#   download  <URL> <DEST> [SHA256]                     — fetch a file (progress on stdout)
#   write-usb <DEVICE> <ISO> <PRESET_JSON> [EXTRAS_DIR] — GPT + FAT32 ESP install USB (needs root)
#
# Progress markers on stdout: PROGRESS:NN msg / LOG:msg / ERROR:msg — the GUI
# parses these to drive its progress bar. Partition/format/copy logic mirrors the
# in-OS freezeos-make-install-usb-helper.sh (proven), minus the FreezeOS-only bits.
#
# EXTRAS_DIR (optional): a staged tree copied verbatim onto the USB root after
# the ISO contents — used for per-device payloads (boot/freezeos/payload/…).
set -euo pipefail
log()  { echo "LOG:$*"; }
prog() { echo "PROGRESS:$1 $2"; }
err()  { echo "ERROR:$*"; exit 1; }

# Removable-device safety gate. FREEZEOS_TEST_ALLOW_NONREMOVABLE=1 skips it for
# automated loopback tests ONLY — pkexec strips the environment, so the normal
# GUI → pkexec path can never reach the bypass.
check_target_disk() {  # $1 = device
    local dev="$1" rm tran hotplug
    [ -b "$dev" ] || err "not a block device: $dev"
    if [ "${FREEZEOS_TEST_ALLOW_NONREMOVABLE:-}" = "1" ]; then
        log "TEST MODE: skipping removable-device check for $dev"
        return 0
    fi
    case "$dev" in /dev/sd*|/dev/mmcblk*|/dev/nvme*) : ;; *) err "refusing non-disk device: $dev" ;; esac
    rm=$(lsblk -dnro RM "$dev" 2>/dev/null || echo 0)
    tran=$(lsblk -dnro TRAN "$dev" 2>/dev/null || echo "")
    hotplug=$(lsblk -dnro HOTPLUG "$dev" 2>/dev/null || echo 0)
    [ "$rm" = "1" ] || [ "$tran" = "usb" ] || [ "$hotplug" = "1" ] \
        || err "refusing non-removable / non-USB device: $dev (rm=$rm tran=$tran hotplug=$hotplug)"
}

case "${1:-help}" in

  download)
    URL="${2:?url}"; DEST="${3:?dest}"; WANT_SHA="${4:-}"
    mkdir -p "$(dirname "$DEST")"
    prog 5 "Downloading…"
    rm -f "$DEST.part"
    curl -fLsS --max-time 1200 -o "$DEST.part" "$URL" >/tmp/fz-usb-curl.log 2>&1 &
    CPID=$!
    # size-based progress (server sends Content-Length; poll the .part file)
    TOTAL=$(curl -fsSI --max-time 20 "$URL" 2>/dev/null | awk 'tolower($1)=="content-length:"{print $2}' | tr -d '\r' | tail -1)
    : "${TOTAL:=0}"
    set +e
    while kill -0 "$CPID" 2>/dev/null; do
      sleep 1
      cur=$(stat -c%s "$DEST.part" 2>/dev/null); : "${cur:=0}"
      if [ "$TOTAL" -gt 0 ]; then
        pct=$((cur*100/TOTAL)); [ "$pct" -gt 100 ] && pct=100
        prog $((5 + pct*25/100)) "Downloading — $((cur/1048576)) / $((TOTAL/1048576)) MB (${pct}%)"
      else
        prog 10 "Downloading — $((cur/1048576)) MB"
      fi
    done
    wait "$CPID"; RC=$?; set -e
    [ "$RC" -eq 0 ] || { log "curl: $(tail -2 /tmp/fz-usb-curl.log 2>/dev/null | tr '\n' ' ')"; rm -f "$DEST.part"; err "download failed (curl rc=$RC)"; }
    if [ -n "$WANT_SHA" ]; then
      prog 30 "Verifying checksum…"
      got=$(sha256sum "$DEST.part" | awk '{print $1}')
      [ "$got" = "$WANT_SHA" ] || { rm -f "$DEST.part"; err "checksum mismatch (expected $WANT_SHA got $got)"; }
    fi
    mv "$DEST.part" "$DEST"; rm -f /tmp/fz-usb-curl.log
    log "installer at $DEST"; echo "ISO_PATH:$DEST"
    ;;

  write-usb)
    DEVICE="${2:?device}"; ISO="${3:?iso}"; PRESET="${4:?preset}"; EXTRAS="${5:-}"
    [ "$(id -u)" -eq 0 ] || err "write-usb must run as root (invoke via pkexec)"
    check_target_disk "$DEVICE"
    [ -f "$ISO" ] || err "ISO not found: $ISO"
    [ -f "$PRESET" ] || err "preset not found: $PRESET"

    prog 32 "Unmounting existing partitions on $DEVICE…"
    for p in $(ls "${DEVICE}"* 2>/dev/null | grep -v "^${DEVICE}$" || true); do umount "$p" 2>/dev/null || true; done

    prog 36 "Zapping partition table…"
    sgdisk --zap-all "$DEVICE" >/dev/null 2>&1 || true
    wipefs -af "$DEVICE" >/dev/null 2>&1 || true

    # Label MUST be FREEZEOS (the install-USB label), NOT FREEZEBOOT:
    #  • freezeos-init's boot-logger + sidecar scan look for FREEZEOS on
    #    install media; a FREEZEBOOT-labeled single-FAT stick gets grabbed
    #    RW by the early /efilog trace and every later ro scan mount EBUSYs
    #    → "No sidecar rootfs found" → busybox shell (found 2026-08-16 in a
    #    VirtualBox boot test of exactly this helper's output).
    #  • FREEZEBOOT is the INSTALLED disk's /boot label — an installer stick
    #    carrying it collides with the target after install.
    prog 40 "Creating GPT + FAT32 ESP (label FREEZEOS)…"
    sgdisk -n 1:2048:0 -t 1:EF00 -c 1:"FREEZEOS" "$DEVICE" >/dev/null
    partprobe "$DEVICE" 2>/dev/null || true; udevadm settle
    if [[ "$DEVICE" =~ [0-9]$ ]]; then PART="${DEVICE}p1"; else PART="${DEVICE}1"; fi
    [ -b "$PART" ] || { sleep 2; [ -b "$PART" ] || err "partition $PART not visible after sgdisk"; }

    prog 48 "Formatting $PART as FAT32…"
    mkfs.vfat -F 32 -n "FREEZEOS" "$PART" >/dev/null

    MNT_USB=$(mktemp -d -p /tmp fz-usb-XXXXXX); MNT_ISO=$(mktemp -d -p /tmp fz-iso-XXXXXX)
    cleanup(){ umount "$MNT_ISO" 2>/dev/null || true; umount "$MNT_USB" 2>/dev/null || true; rmdir "$MNT_ISO" "$MNT_USB" 2>/dev/null || true; }
    trap cleanup EXIT

    prog 52 "Mounting…"; mount "$PART" "$MNT_USB"; mount -o loop,ro "$ISO" "$MNT_ISO"
    prog 55 "Copying installer contents (slow step)…"
    TOTAL=$(du -sb "$MNT_ISO" 2>/dev/null | awk '{print $1}'); : "${TOTAL:=0}"
    # FAT32 can't hold Unix ownership/xattrs — copy without preserving them.
    cp -rT --preserve=mode,timestamps --no-preserve=ownership,xattr,context,links "$MNT_ISO" "$MNT_USB" 2>/tmp/fz-cp.log &
    CPID=$!
    while kill -0 "$CPID" 2>/dev/null; do
      sleep 1
      UKB=$(df --output=used --block-size=1K "$MNT_USB" 2>/dev/null | tail -1 | tr -d ' '); : "${UKB:=0}"
      UB=$((UKB*1024))
      if [ "$TOTAL" -gt 0 ]; then
        cp_pct=$((UB*100/TOTAL)); [ "$cp_pct" -gt 100 ] && cp_pct=100
        prog $((55 + cp_pct*30/100)) "Copying $((UB/1048576)) / $((TOTAL/1048576)) MB (${cp_pct}%)"
      fi
    done
    wait "$CPID"; CRC=$?
    [ "$CRC" -eq 0 ] || { log "cp: $(tail -3 /tmp/fz-cp.log 2>/dev/null | tr '\n' ' ')"; err "cp failed rc=$CRC"; }
    rm -f /tmp/fz-cp.log
    sync

    prog 88 "Writing install preset + first-boot marker…"
    cp "$PRESET" "$MNT_USB/freezeos-install.json"; chmod 644 "$MNT_USB/freezeos-install.json"
    mkdir -p "$MNT_USB/freezeos"; touch "$MNT_USB/freezeos/first-boot"

    if [ -n "$EXTRAS" ] && [ -d "$EXTRAS" ]; then
      prog 90 "Writing per-device extras (payload)…"
      cp -rT --preserve=mode,timestamps --no-preserve=ownership,xattr,context,links \
         "$EXTRAS" "$MNT_USB" 2>/dev/null || log "extras copy had warnings (FAT32 attrs — expected)"
    fi

    prog 95 "Syncing + unmounting…"
    sync; umount "$MNT_ISO"; umount "$MNT_USB"; rmdir "$MNT_ISO" "$MNT_USB" 2>/dev/null || true; trap - EXIT
    partprobe "$DEVICE" 2>/dev/null || true; udevadm settle
    prog 98 "Ejecting…"
    eject "$DEVICE" 2>/dev/null || udisksctl power-off -b "$DEVICE" 2>/dev/null || true
    prog 100 "Done"
    log "Installer USB written + ejected — SAFE TO REMOVE. Boot the target PC from it."
    ;;

  # ── Write a personalized FreezeOS SYSTEM image (gzip) raw to the USB, so the
  #    stick boots as an installed FreezeOS (portable). $4 = uncompressed size
  #    for the progress bar.
  write-image)
    IMG="${2:?img}"; DEVICE="${3:?device}"; RAWSIZE="${4:-0}"
    [ "$(id -u)" -eq 0 ] || err "write-image must run as root (invoke via pkexec)"
    check_target_disk "$DEVICE"
    [ -f "$IMG" ] || err "image not found: $IMG"

    prog 30 "Unmounting existing partitions on $DEVICE…"
    for p in $(ls "${DEVICE}"* 2>/dev/null | grep -v "^${DEVICE}$" || true); do umount "$p" 2>/dev/null || true; done

    prog 32 "Writing FreezeOS system image to $DEVICE (this is the slow step)…"
    _w="/tmp/fz-write.$$"
    ( set -o pipefail; gunzip -c "$IMG" | dd of="$DEVICE" bs=4M conv=fsync status=progress 2>"$_w.dd"; echo "${PIPESTATUS[@]}" >"$_w.rc" ) &
    WPID=$!
    while kill -0 "$WPID" 2>/dev/null; do
      sleep 2
      b=$(tr '\r' '\n' <"$_w.dd" 2>/dev/null | grep -oE '^[0-9]+ bytes' | tail -1 | grep -oE '^[0-9]+')
      if [ -n "$b" ] && [ "${RAWSIZE:-0}" -gt 0 ]; then
        pct=$((b*100/RAWSIZE)); [ "$pct" -gt 100 ] && pct=100
        prog $((32 + pct*63/100)) "Writing $((b/1073741824)) / $((RAWSIZE/1073741824)) GB (${pct}%)"
      fi
    done
    wait "$WPID" || true
    RC=$(cat "$_w.rc" 2>/dev/null || echo "1 1"); rm -f "$_w.dd" "$_w.rc"
    [ "$RC" = "0 0" ] || err "image write failed (pipestatus='$RC')"

    prog 96 "Flushing + settling…"
    sync; partprobe "$DEVICE" 2>/dev/null || true; udevadm settle
    prog 98 "Ejecting…"
    eject "$DEVICE" 2>/dev/null || udisksctl power-off -b "$DEVICE" 2>/dev/null || true
    prog 100 "Done"
    log "FreezeOS installed + ejected — SAFE TO REMOVE. Boot the target machine from it."
    ;;

  *) echo "usage: $0 download <URL> <DEST> [SHA256] | write-usb <DEVICE> <ISO> <PRESET_JSON> [EXTRAS_DIR] | write-image <IMG.gz> <DEVICE> <RAWSIZE>"; exit 1 ;;
esac
