#!/bin/bash
#
# munbyn-thermal-autoconf - find a Munbyn thermal receipt printer in the
# local network and announce it via mDNS (Avahi), so it appears in the
# printer dialogs of any desktop and can be added there in the usual way.
#
# The printer itself does not announce; this service does it on its behalf.
# By default no queue is created - the user adds the printer himself.
# Setting AUTOSETUP=yes below additionally creates the queue automatically.
#
# To disable everything:  systemctl mask --now munbyn-thermal.service
#
# SPDX-License-Identifier: MIT
# Copyright (C) 2026 Christian Kvasny <chris@ckvsoft.at>

set -u
export PATH="$PATH:/usr/sbin:/sbin"

PPD_PATH="/usr/share/cups/model/Munbyn/munbyn-itpp047.ppd"
SETUP="${MUNBYN_SETUP:-munbyn-thermal-setup}"
CONF_DIR="/etc/munbyn-thermal"
MDNS_CONF="${MUNBYN_MDNS_CONF:-$CONF_DIR/mdns.conf}"
DRYRUN="${MUNBYN_DRYRUN:-no}"

NICE_NAME="Munbyn ITPP047/ITPP098 (80 mm)"
QUEUE="Munbyn-ITPP047"
AUTOSETUP=no
ANNOUNCE=yes
SETDEFAULT=no
INTERVAL=30

pinned_ip=""
if [ -r "$MDNS_CONF" ]; then
    # shellcheck disable=SC1090
    . "$MDNS_CONF"
    pinned_ip="${IP:-}"
fi

log() { echo "munbyn-thermal: $*"; }
have() { command -v "$1" >/dev/null 2>&1; }

# --- optional mDNS announcement (off by default) --------------------------

pub_addr=""; pub_svc=""; pub_ip=""

stop_pub() {
    [ -n "$pub_addr" ] && kill "$pub_addr" 2>/dev/null
    [ -n "$pub_svc" ] && kill "$pub_svc" 2>/dev/null
    pub_addr=""; pub_svc=""; pub_ip=""
}

start_pub() {
    local ip="$1" host="munbyn-$(echo "$1" | tr . -).local"
    have avahi-publish-service || { log "avahi-utils fehlt - Ankündigung übersprungen"; return 0; }
    avahi-publish-address -a "$host" "$ip" & pub_addr=$!
    avahi-publish-service -H "$host" "Munbyn ITPP047" _pdl-datastream._tcp 9100 \
        "txtvers=1" "qtotal=1" \
        "ty=$NICE_NAME" "product=(Munbyn ITPP047)" \
        "usb_MFG=Munbyn" "usb_MDL=ITPP047" \
        "pdl=application/octet-stream" "note=Munbyn POS" "priority=25" & pub_svc=$!
    pub_ip="$ip"
    log "$ip angekündigt als $host"
}

ensure_pub() {
    local ip="$1"
    if [ "$pub_ip" = "$ip" ] && [ -n "$pub_svc" ] && kill -0 "$pub_svc" 2>/dev/null; then
        return 0
    fi
    stop_pub
    start_pub "$ip"
}

# --- CUPS queue (self-healing) --------------------------------------------

ensure_queue() {
    local ip="$1"
    [ "$AUTOSETUP" = yes ] || return 0
    [ -f "$PPD_PATH" ] || return 0

    # Never create a second queue for the same printer: skip if a queue
    # already points at it - either directly (socket://) or via our mDNS
    # announcement (dnssd://Munbyn%20ITPP047...).
    if lpstat -v 2>/dev/null | grep -qE "socket://$ip:9100|Munbyn%20ITPP047"; then
        return 0
    fi
    if [ "$DRYRUN" = yes ]; then
        log "würde Queue '$QUEUE' -> socket://$ip:9100 anlegen"
        return 0
    fi

    if lpadmin -p "$QUEUE" -E -v "socket://$ip:9100" -P "$PPD_PATH" \
            -D "$NICE_NAME" \
            -o MunbynPaperReduction=Bottom -o MunbynCutAfterJob=Partial 2>/dev/null; then
        cupsenable "$QUEUE" 2>/dev/null || true
        cupsaccept "$QUEUE" 2>/dev/null || true
        [ "$SETDEFAULT" = yes ] && lpadmin -d "$QUEUE" 2>/dev/null || true
        log "Queue '$QUEUE' -> socket://$ip:9100 angelegt"
    else
        log "Queue-Anlage fehlgeschlagen"
    fi
}

# --- main loop ------------------------------------------------------------

cur=""
trap 'stop_pub; exit 0' TERM INT

while :; do
    ip="$pinned_ip"
    if [ -z "$ip" ]; then
        if [ -n "$cur" ] && "$SETUP" --probe "$cur" >/dev/null 2>&1; then
            ip="$cur"
        else
            ip="$("$SETUP" --detect 2>/dev/null || true)"
        fi
    fi
    cur="$ip"

    if [ -n "$ip" ]; then
        if [ "$ANNOUNCE" = yes ]; then ensure_pub "$ip"; else stop_pub; fi
        ensure_queue "$ip"
    else
        stop_pub
        log "kein ESC/POS-Drucker gefunden"
    fi

    sleep "$INTERVAL"
done
