#!/bin/sh
# Schaltet die ninlight-Recovery-Station an und aus.
#
# Die Station ist absichtlich nicht dauerhaft an: Solange sie laeuft, kann jeder
# in Funkreichweite mit dem Passwort einer Lampe beim naechsten Boot beliebige
# Firmware unterschieben, und der Werksreset per fuenf Stromzyklen funktioniert
# bei keiner Lampe in Reichweite mehr (die Firmware loescht den Zaehler vor
# jedem Recovery-Versuch).
set -eu

CONF=/etc/ninlight-station.conf
if [ -r "$CONF" ]; then
    # shellcheck disable=SC1090
    . "$CONF"
elif [ -e "$CONF" ]; then
    # $CONF ist 0600 root:root, damit das Passwort nicht fuer jeden lesbar
    # ist. Der dokumentierte Aufruf "ssh <pi-host> ninlight-station on" laeuft
    # aber als normaler Benutzer - "sudo cat" liest die Datei ein, ohne ihre
    # Rechte aufzuweichen.
    eval "$(sudo cat "$CONF")"
else
    echo "Fehler: $CONF fehlt - zuerst tools/station/setup_pi.sh ausfuehren" >&2
    exit 1
fi

for _key in SSID PSK IMAGE_DIR HOME_CONNECTION AP_CONNECTION; do
    eval "test -n \"\${$_key-}\"" || {
        echo "Fehler: $CONF: Schluessel $_key fehlt oder ist leer - tools/station/setup_pi.sh ausfuehren" >&2
        exit 1
    }
done
unset _key

need_profile() {
    nmcli -t -f NAME con show | grep -qx "$AP_CONNECTION" || {
        echo "Fehler: NetworkManager-Profil '$AP_CONNECTION' fehlt - tools/station/setup_pi.sh ausfuehren" >&2
        exit 1
    }
}

images() {
    find "$IMAGE_DIR" -maxdepth 1 -name 'ninlight_*_ota.img' 2>/dev/null | sort
}

case "${1:-}" in
on)
    need_profile
    n=$(images | wc -l | tr -d ' ')
    [ "$n" -gt 0 ] || echo "Warnung: $IMAGE_DIR enthaelt kein Image - die Station antwortet auf alles mit 404" >&2
    sudo nmcli con up "$AP_CONNECTION" >/dev/null
    # Eine fruehere Absturzserie darf den naechsten ehrlichen Versuch nicht
    # blockieren (systemd verweigert "start" sonst sofort mit "start-limit-hit").
    sudo systemctl reset-failed ninlight-station 2>/dev/null || true
    if ! sudo systemctl start ninlight-station; then
        # Der Start-Aufruf selbst ist gescheitert (z.B. start-limit-hit) - unter
        # set -eu wuerde das Skript hier sonst abbrechen, bevor die
        # Lebendigkeitspruefung unten je erreicht wird, und der eben
        # hochgefahrene Zugangspunkt bliebe offen ohne Server dahinter stehen.
        sudo nmcli con down "$AP_CONNECTION" >/dev/null 2>&1 || true
        echo "Fehler: ninlight-station liess sich nicht starten - Zugangspunkt wieder abgeschaltet. Details: journalctl -u ninlight-station" >&2
        exit 1
    fi
    # "systemctl start" meldet bei Type=simple schon Erfolg, sobald der Prozess
    # gestartet wurde - nicht, sobald er ueberlebt hat. Kurz warten und wirklich
    # nachsehen, sonst bleibt ein offener AP ohne Server dahinter stehen.
    sleep 1
    if systemctl is-active --quiet ninlight-station; then
        echo "Station an: SSID $SSID auf 192.168.8.1, $n Image(s)"
        echo "Nicht vergessen: 'ninlight-station off', wenn du fertig bist."
    else
        # Mit Restart=always laeuft ein abgestuerzter Dienst sonst im Hintergrund
        # weiter in seiner Neustartschleife - erst stoppen, dann den AP runter,
        # sonst suggeriert die Meldung unten einen saubereren Zustand als er ist.
        sudo systemctl stop ninlight-station 2>/dev/null || true
        sudo nmcli con down "$AP_CONNECTION" >/dev/null 2>&1 || true
        echo "Fehler: ninlight-station ist nach dem Start nicht aktiv - Zugangspunkt wieder abgeschaltet. Details: journalctl -u ninlight-station" >&2
        exit 1
    fi
    ;;
off)
    sudo systemctl stop ninlight-station 2>/dev/null || true
    sudo nmcli con down "$AP_CONNECTION" >/dev/null 2>&1 || true
    if nmcli -t -f NAME con show | grep -qx "$HOME_CONNECTION"; then
        if sudo nmcli con up "$HOME_CONNECTION" >/dev/null; then
            echo "Station aus, wlan0 zurueck im Heim-WLAN ($HOME_CONNECTION)"
        else
            echo "Station aus. Zurueckschalten zu '$HOME_CONNECTION' fehlgeschlagen - wlan0-Status pruefen." >&2
        fi
    else
        echo "Station aus. Profil '$HOME_CONNECTION' fehlt, wlan0 bleibt ungenutzt - der Zugang ueber Kabel ist davon nicht betroffen." >&2
    fi
    ;;
status)
    # "systemctl is-active" schreibt den Zustand ("inactive", "failed", ...) auf stdout und
    # liefert dabei einen Rueckgabewert ungleich 0, sobald der Dienst nicht "active" ist -
    # ein "|| echo inaktiv" wuerde also zusaetzlich zur ersten Zeile ausgeloest und beide
    # landen in der Ausgabe. Der Zustand selbst ist die Auskunft; "status" ist damit
    # erfolgreich, sobald es ihn ermitteln konnte, unabhaengig vom Dienstzustand - deshalb
    # am Ende explizit exit 0.
    printf 'Dienst : %s\n' "$(systemctl is-active ninlight-station 2>/dev/null || true)"
    printf 'wlan0  : %s\n' "$(nmcli -t -f GENERAL.CONNECTION device show wlan0 2>/dev/null | cut -d: -f2)"
    printf 'Adresse: %s\n' "$(ip -4 -br addr show wlan0 2>/dev/null | awk '{print $3}')"
    echo "Images :"
    images | while read -r f; do
        printf '  %-34s %s\n' "$(basename "$f")" \
            "$(python3 - "$f" <<'PY'
import pathlib, sys
t = pathlib.Path(sys.argv[1]).read_bytes()[-512:]
print(t[21:37].rstrip(b"\x00").decode("ascii", "replace") if t[:4] == b"NINL" else "kein Trailer")
PY
)"
    done
    # "status" soll mit 0 enden, sobald es seine Auskunft geben konnte, auch wenn noch nie
    # ausgeliefert wurde - ohne das "|| true" waere der Exit-Code des Skripts hier der des
    # fehlgeschlagenen Tests (1), weil das die letzte Anweisung im Zweig ist.
    [ -r /run/ninlight-station/status.json ] && { echo "Zuletzt ausgeliefert:"; sed 's/^/  /' /run/ninlight-station/status.json; }
    exit 0
    ;;
*)
    echo "Aufruf: ninlight-station on|off|status" >&2
    exit 2
    ;;
esac
