#!/usr/bin/env bash
# Offload already-rotated luxury capture siblings to Dropbox, then delete local.
#
# Does NOT touch live basenames (events.jsonl, packets.raw, …) — the bridge/listen
# process may still hold those FDs open. Upload is async relative to copper/HS;
# never call this from try_rotate_debug_logs / the capture tick.
#
# Usage (Pi):
#   cd ~/EtherGold/sync
#   DRY_RUN=1 bash offload_rotated_capture.sh
#   bash offload_rotated_capture.sh
#
# Timer: bash install_offload_rotated_capture_schedule.sh
# Safe no-op if rclone.env is missing (bench seats without sync yet).

if grep -q $'\r' "${BASH_SOURCE[0]}" 2>/dev/null; then
  sed -i 's/\r$//' "${BASH_SOURCE[0]}"
  exec bash "${BASH_SOURCE[0]}" "$@"
fi

set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="${ROOT}/rclone.env"
DRY_RUN="${DRY_RUN:-0}"

if [[ -f "${ROOT}/ethergold_paths.sh" ]]; then
  # shellcheck source=ethergold_paths.sh
  source "${ROOT}/ethergold_paths.sh"
fi
ETHERGOLD_ROOT="${ETHERGOLD_ROOT:-/home/topbox/EtherGold}"
ETHERGOLD_LOGS="${ETHERGOLD_LOGS:-${ETHERGOLD_ROOT}/logs}"
TRANSCRIPT="${ETHERGOLD_LOGS}/.offload_rotated_last.log"

mkdir -p "${ETHERGOLD_LOGS}"
: > "${TRANSCRIPT}"

log() {
  printf '%s %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$*" | tee -a "${TRANSCRIPT}"
}

if [[ ! -f "${ENV_FILE}" ]]; then
  log "skip: missing ${ENV_FILE} (no-op)"
  exit 0
fi

if grep -q $'\r' "${ENV_FILE}" 2>/dev/null; then
  sed -i 's/\r$//' "${ENV_FILE}"
fi

# shellcheck source=/dev/null
source "${ENV_FILE}"

RCLONE_REMOTE="${RCLONE_REMOTE:-}"
DROPBOX_DEST="${DROPBOX_DEST:-}"
SYNC_SOURCE="${SYNC_SOURCE:-dev}"

if [[ -z "${RCLONE_REMOTE}" || -z "${DROPBOX_DEST}" ]]; then
  log "skip: RCLONE_REMOTE / DROPBOX_DEST unset in rclone.env (no-op)"
  exit 0
fi

if ! command -v rclone >/dev/null 2>&1; then
  log "ERROR: rclone not installed"
  exit 1
fi

resolve_source() {
  local candidate="${1:-dev}"
  if [[ "${candidate}" != /* ]]; then
    candidate="${ETHERGOLD_ROOT}/${candidate#./}"
  fi
  printf '%s\n' "${candidate}"
}

SOURCE="$(resolve_source "${SYNC_SOURCE}")"
DATA_DIR="${SOURCE}/data"
REMOTE_DATA="${RCLONE_REMOTE}:${DROPBOX_DEST}/data"

if [[ ! -d "${DATA_DIR}" ]]; then
  log "skip: no data dir ${DATA_DIR}"
  exit 0
fi

# Rotated siblings only — prefix match, never the live basename.
list_rotated() {
  local base
  (
    cd "${DATA_DIR}" || exit 0
    shopt -s nullglob
    for base in events.jsonl packets.raw inject_echo.jsonl hw_debug.jsonl; do
      for f in "${base}".*; do
        [[ -f "${f}" ]] || continue
        # Guard: basename itself must not match (nullglob shouldn't, but be explicit).
        [[ "${f}" == "${base}" ]] && continue
        printf '%s\n' "${f}"
      done
    done
    shopt -u nullglob
  ) | LC_ALL=C sort -u
}

mapfile -t ROTATED < <(list_rotated)
if [[ "${#ROTATED[@]}" -eq 0 ]]; then
  log "ok: no rotated capture files under ${DATA_DIR}"
  exit 0
fi

log "=== offload_rotated_capture ==="
log "source: ${DATA_DIR}"
log "remote: ${REMOTE_DATA}"
log "files: ${#ROTATED[@]}"

file_size_bytes() {
  local path="${1}"
  if stat -c '%s' "${path}" >/dev/null 2>&1; then
    stat -c '%s' "${path}"
  else
    stat -f '%z' "${path}"
  fi
}

remote_size_of() {
  local name="${1}"
  # rclone size on a single file prints "Total size: N (N Byte)"
  rclone size "${REMOTE_DATA}/${name}" 2>/dev/null \
    | awk '/Total size:/ {
        for (i = 1; i <= NF; i++) if ($i ~ /^[0-9]+$/) { print $i; exit }
      }' || true
}

COPIED=0
DELETED=0
FAILED=0

for name in "${ROTATED[@]}"; do
  local_path="${DATA_DIR}/${name}"
  [[ -f "${local_path}" ]] || continue
  sz="$(file_size_bytes "${local_path}")"
  log "candidate: ${name} (${sz} bytes)"

  if [[ "${DRY_RUN}" == "1" ]]; then
    log "DRY_RUN: would rclone copy → delete ${name}"
    COPIED=$((COPIED + 1))
    continue
  fi

  if ! rclone copyto "${local_path}" "${REMOTE_DATA}/${name}" --retries 3; then
    log "ERROR: rclone copy failed for ${name}"
    FAILED=$((FAILED + 1))
    continue
  fi

  rem_sz="$(remote_size_of "${name}")"
  if [[ -n "${rem_sz}" && "${rem_sz}" != "${sz}" ]]; then
    log "ERROR: size mismatch ${name} local=${sz} remote=${rem_sz} — keeping local"
    FAILED=$((FAILED + 1))
    continue
  fi

  if rm -f "${local_path}"; then
    log "deleted local: ${name}"
    DELETED=$((DELETED + 1))
    COPIED=$((COPIED + 1))
  else
    log "WARN: copied but could not delete ${local_path}"
    COPIED=$((COPIED + 1))
  fi
done

log "done: copied=${COPIED} deleted=${DELETED} failed=${FAILED} dry_run=${DRY_RUN}"
if [[ "${FAILED}" -gt 0 ]]; then
  exit 1
fi
exit 0
