#!/bin/sh
set -eu
SOCK="${CUPS_SERVER_SOCK:-/var/run/cups/cups.sock}"
QUEUE="${HBP_QUEUE:-test-hbp}"
GADGET_DEV="${HBP_GADGET_DEV:-/dev/ttyGS1}"
GADGET_WRITE_TIMEOUT_SEC="${HBP_GADGET_WRITE_TIMEOUT_SEC:-45}"
PDF="${1:-}"
DPI="${2:-600}"
if [ -z "$PDF" ] || [ ! -f "$PDF" ]; then
  echo "usage: print-hbp-pdf /path/to/file.pdf [dpi]" >&2
  exit 2
fi
case "$DPI" in
  ''|*[!0-9]*)
    echo "invalid dpi: '$DPI'" >&2
    exit 2
    ;;
esac
if [ "$DPI" -lt 300 ] || [ "$DPI" -gt 1200 ]; then
  echo "dpi out of range: $DPI (expected 300..1200)" >&2
  exit 2
fi

# Brother HBP via brlaser currently produces wrong geometry when fed 1200dpi
# cups-raster in this environment. Keep raster path at 600dpi for correctness.
EFFECTIVE_DPI="$DPI"
if [ "$DPI" -gt 600 ]; then
  EFFECTIVE_DPI=600
  echo "print-hbp-pdf: requested ${DPI}dpi, using ${EFFECTIVE_DPI}dpi for correct geometry on HBP path" >&2
fi

ensure_runtime_tools() {
  command -v lpadmin >/dev/null 2>&1 && command -v lpstat >/dev/null 2>&1 && return 0

  # Recovery path after SD detach: restore /nix from RAM-backed stage, if present.
  if [ -d /run/hbp-ram-runtime/nix/store ]; then
    mount --bind /run/hbp-ram-runtime/nix /nix >/dev/null 2>&1 || true
  fi

  command -v lpadmin >/dev/null 2>&1 && command -v lpstat >/dev/null 2>&1
}

OUTPUT_MODE=""
detect_output_mode() {
  if ls /dev/usb/lp* >/dev/null 2>&1; then
    OUTPUT_MODE="cups"
    return 0
  fi
  if [ -c "$GADGET_DEV" ]; then
    OUTPUT_MODE="gadget"
    return 0
  fi
  return 1
}

if ! detect_output_mode; then
  echo "print-hbp-pdf: no printer path available (/dev/usb/lp* or ${GADGET_DEV})" >&2
  exit 5
fi

ensure_cupsd_running() {
  if [ -S "$SOCK" ]; then
    return 0
  fi
  if [ -x /bin/cupsd ]; then
    /bin/cupsd >/log/cups.log 2>&1 || true
    sleep 1
  fi
  [ -S "$SOCK" ]
}

ensure_hbp_queue() {
  lpstat -h "$SOCK" -p "$QUEUE" >/dev/null 2>&1 && return 0

  URI=""
  if lpstat -h "$SOCK" -p test >/dev/null 2>&1; then
    URI="$(lpstat -h "$SOCK" -v 2>/dev/null | awk '$1=="device" && $3=="test:" {print $4; exit}')"
  fi
  if [ -z "$URI" ] && [ -x /var/cups-serverbin/lib/cups/backend/usb ]; then
    URI="$(/var/cups-serverbin/lib/cups/backend/usb 2>/dev/null | awk '$1=="direct" && $2 ~ /^usb:\/\// {print $2; exit}')"
  fi
  [ -n "$URI" ] || return 1

  model_from_uri() {
    # usb://Brother/HL-L5000D%20series?serial=... -> HL-L5000D series
    printf '%s' "$1" | sed -n 's@^usb://Brother/\([^?]*\).*$@\1@p' | sed 's/%20/ /g'
  }
  MODEL_NAME="$(model_from_uri "$URI")"
  find_brlaser_ppd() {
    model="$1"
    model_dir="/var/cups-data/model"
    [ -d "$model_dir" ] || return 0

    if [ -n "$model" ]; then
      # Fast path: direct filename match.
      ppd="$(find "$model_dir" -type f \( -iname "*${model}*.ppd" -o -iname "*${model}*.ppd.gz" \) | head -n 1)"
      [ -n "$ppd" ] && { echo "$ppd"; return 0; }

      # ppdc-generated brlaser files are often named like brl5000d.ppd, so also match content.
      ppd="$(grep -RilsF "ModelName: \"Brother $model\"" "$model_dir" 2>/dev/null | head -n 1)"
      [ -n "$ppd" ] && { echo "$ppd"; return 0; }

      ppd="$(grep -RilsF "MDL:$model;" "$model_dir" 2>/dev/null | head -n 1)"
      [ -n "$ppd" ] && { echo "$ppd"; return 0; }
    fi

    find "$model_dir" -type f \
      \( -iname 'brl*.ppd' -o -iname 'brl*.ppd.gz' -o -iname '*Brother*HL-*.ppd' -o -iname '*Brother*HL-*.ppd.gz' \) \
      | head -n 1
  }
  run_ppdc_brlaser() {
    out_dir="$1"
    drv_file="$2"
    [ -n "$out_dir" ] && [ -n "$drv_file" ] || return 1
    set -- /bin/ppdc -d "$out_dir"
    for inc in /var/cups-data/ppdc /var/cups-data/drv; do
      [ -d "$inc" ] || continue
      set -- "$@" -I "$inc"
    done
    CUPS_BIN_ROOT="$(readlink /bin/cupsd 2>/dev/null | sed 's#/bin/cupsd$##')"
    if [ -n "$CUPS_BIN_ROOT" ] && [ -d "$CUPS_BIN_ROOT/share/cups/ppdc" ]; then
      set -- "$@" -I "$CUPS_BIN_ROOT/share/cups/ppdc"
    elif [ -n "$CUPS_BIN_ROOT" ] && [ -d "${CUPS_BIN_ROOT}-lib/share/cups/ppdc" ]; then
      set -- "$@" -I "${CUPS_BIN_ROOT}-lib/share/cups/ppdc"
    fi
    set -- "$@" "$drv_file"
    /bin/timeout 60 "$@" >/tmp/ppdc-hbp.out 2>/tmp/ppdc-hbp.err
  }

  # Prefer PPD path to avoid cups-driverd/dvr:/// dependency.
  PPD=""
  if [ -d /var/cups-data/model ]; then
    PPD="$(find_brlaser_ppd "$MODEL_NAME")"
  fi
  if [ -z "$PPD" ] && [ -x /bin/ppdc ] && [ -f /var/cups-data/drv/brlaser.drv ]; then
    mkdir -p /var/cups-data/model
    run_ppdc_brlaser /var/cups-data/model /var/cups-data/drv/brlaser.drv || true
    PPD="$(find_brlaser_ppd "$MODEL_NAME")"
  fi

  echo "print-hbp-pdf: queue='$QUEUE' model='$MODEL_NAME' uri='$URI' ppd='${PPD:-<none>}' dpi='$DPI' effective_dpi='$EFFECTIVE_DPI'" >&2
  lpadmin -h "$SOCK" -x "$QUEUE" >/dev/null 2>&1 || true
  if [ -n "$PPD" ]; then
    if ! lpadmin -h "$SOCK" -p "$QUEUE" -E -v "$URI" -P "$PPD" >/tmp/lpadmin-hbp.out 2>/tmp/lpadmin-hbp.err; then
      echo "lpadmin failed while creating '$QUEUE' (see /tmp/lpadmin-hbp.err)" >&2
      return 1
    fi
  else
    echo "no usable PPD for '$QUEUE' (ppdc may have failed; see /tmp/ppdc-hbp.err)" >&2
    return 1
  fi
  if ! lpstat -h "$SOCK" -p "$QUEUE" >/dev/null 2>&1; then
    echo "queue '$QUEUE' still missing after lpadmin (see /tmp/lpadmin-hbp.err)" >&2
    return 1
  fi
}

ensure_queue_ready() {
  lpadmin -h "$SOCK" -p "$QUEUE" -E >/dev/null 2>&1 || true
  if command -v cupsenable >/dev/null 2>&1; then
    cupsenable -h "$SOCK" "$QUEUE" >/dev/null 2>&1 || true
  fi
  if command -v cupsaccept >/dev/null 2>&1; then
    cupsaccept -h "$SOCK" "$QUEUE" >/dev/null 2>&1 || true
  fi
}

RAS="/tmp/print-hbp.ras"
gs -q -dSAFER -dBATCH -dNOPAUSE -sDEVICE=cups -sOutputFile="$RAS" -r"$EFFECTIVE_DPI" -dDEVICEWIDTHPOINTS=595 -dDEVICEHEIGHTPOINTS=842 -dFIXEDMEDIA -dPDFFitPage "$PDF"

if [ "$OUTPUT_MODE" = "gadget" ]; then
  if [ ! -s "$RAS" ]; then
    echo "print-hbp-pdf: generated raster is empty" >&2
    exit 6
  fi
  echo "print-hbp-pdf: writing CUPS raster to gadget device ${GADGET_DEV}" >&2
  if ! /bin/timeout "$GADGET_WRITE_TIMEOUT_SEC" sh -c "cat \"$RAS\" > \"$GADGET_DEV\""; then
    echo "print-hbp-pdf: gadget write timed out after ${GADGET_WRITE_TIMEOUT_SEC}s (is host capture active?)" >&2
    exit 7
  fi
  exit 0
fi

if ! ensure_runtime_tools; then
  echo "print-hbp-pdf: CUPS tools unavailable (likely /nix not mounted). Run 'cups-runtime-ram-feasibility stage core' before SD removal." >&2
  exit 4
fi
if ! ensure_cupsd_running; then
  echo "print-hbp-pdf: cupsd socket '$SOCK' not available" >&2
  exit 4
fi
if ! ensure_hbp_queue; then
  echo "queue '$QUEUE' not found on $SOCK and auto-create failed" >&2
  exit 3
fi
ensure_queue_ready

# SeedEtcher expects one immediate physical print, not backlog replay.
# Clear any stale pending jobs on this queue before submitting the new one.
if command -v cancel >/dev/null 2>&1; then
  cancel -h "$SOCK" -a "$QUEUE" >/dev/null 2>&1 || true
fi

lp -h "$SOCK" -d "$QUEUE" \
  -o media=A4 \
  -o Resolution="${EFFECTIVE_DPI}dpi" \
  -o document-format=application/vnd.cups-raster \
  "$RAS"
