#!/usr/bin/env bash
# install-broker-baremetal.sh — installa/configura mosquitto DI SISTEMA come broker
# centrale degli scanner c4rgo (variante bare-metal, non docker). Idempotente.
# Da eseguire come root sul server my.c4rgo.cloud.
#
# PREREQUISITO: la chiave privata della C4rgo-CA (ca.key) + ca.crt, la stessa CA
# che firma i cert dei device. Passali come argomenti o mettili in /etc/mosquitto/certs/.
#
#   sudo ./install-broker-baremetal.sh /percorso/ca.crt /percorso/ca.key
#
# Variabili d'ambiente per il LAB DI TEST (in produzione lasciale ai default,
# cosi' la macchina di test e' identica al server tranne l'indirizzo):
#   EXTRA_SAN=IP:192.168.0.80   SAN aggiuntive nel cert, per farsi validare in TLS
#                               anche quando il bridge punta all'IP invece del nome
#   LOCAL_PORT=1884             porta del listener locale in chiaro, se 1883 e' gia'
#                               occupata sulla macchina di test (poi SCANNER_MQTT_PORT).
#                               Se omessa e il broker e' gia' installato, si conserva
#                               la porta in uso; solo alla prima installazione = 1883.
#   BROKER_CN=altro.host        CN del cert (default my.c4rgo.cloud: NON cambiarlo se
#                               vuoi che il bridge dei device resti identico a prod)
#
#   sudo EXTRA_SAN=IP:192.168.0.80 ./install-broker-baremetal.sh ca.crt ca.key
set -euo pipefail

CN="${BROKER_CN:-my.c4rgo.cloud}"   # deve combaciare con l'address del bridge sui device
EXTRA_SAN="${EXTRA_SAN:-}"          # es. "IP:192.168.0.80" (lab), vuoto in produzione
LOCAL_PORT="${LOCAL_PORT:-}"        # listener in chiaro per il worker, solo su 127.0.0.1
                                    # vuoto = conserva la porta gia' installata (vedi punto 4)
ETC=/etc/mosquitto
CERTS="$ETC/certs"
HERE="$(cd "$(dirname "$0")" && pwd)"

[[ $EUID -eq 0 ]] || { echo "!! Esegui come root (sudo)."; exit 1; }

# 1) mosquitto + utilita' (Debian/Ubuntu). Su altre distro installa a mano.
if ! command -v mosquitto >/dev/null; then
  apt-get update && apt-get install -y mosquitto mosquitto-clients
fi

mkdir -p "$CERTS"

# 2) CA: da argomenti o gia' presente
if [[ $# -ge 1 && -f "$1" ]]; then cp "$1" "$CERTS/ca.crt"; fi
if [[ $# -ge 2 && -f "$2" ]]; then cp "$2" "$CERTS/ca.key"; fi
if [[ ! -f "$CERTS/ca.crt" || ! -f "$CERTS/ca.key" ]]; then
  echo "!! Mancano $CERTS/ca.crt e/o ca.key (C4rgo-CA)."
  echo "   Passali come argomenti: sudo $0 ca.crt ca.key"
  exit 1
fi

# 3) Cert del broker firmato dalla C4rgo-CA, SAN = CN (+ EXTRA_SAN nel lab)
SAN="DNS:$CN"
[[ -n "$EXTRA_SAN" ]] && SAN="$SAN,$EXTRA_SAN"
if [[ ! -f "$CERTS/$CN.crt" ]]; then
  openssl genrsa -out "$CERTS/$CN.key" 2048
  openssl req -new -key "$CERTS/$CN.key" -out "$CERTS/$CN.csr" \
    -subj "/C=IT/ST=Lombardy/O=C4rgo/OU=IoT/CN=$CN"
  printf 'subjectAltName = %s\nextendedKeyUsage = serverAuth\n' "$SAN" > "$CERTS/$CN.ext"
  openssl x509 -req -in "$CERTS/$CN.csr" -CA "$CERTS/ca.crt" -CAkey "$CERTS/ca.key" \
    -CAcreateserial -out "$CERTS/$CN.crt" -days 3650 -sha256 -extfile "$CERTS/$CN.ext"
  rm -f "$CERTS/$CN.csr" "$CERTS/$CN.ext"
  echo ">> Cert broker generato: $CERTS/$CN.crt  (SAN: $SAN)"
else
  echo ">> Cert broker gia' presente: $CERTS/$CN.crt (NON rigenerato). SAN attuali:"
  openssl x509 -in "$CERTS/$CN.crt" -noout -ext subjectAltName | sed 's/^/     /'
  echo "   Se ti serve una SAN diversa (es. un altro IP) cancella $CERTS/$CN.crt e rilancia."
fi

# 4) ACL (riusa quella versionata nel repo) + conf.d
# La conf viene sostituita al volo su CN e porta locale, cosi' un solo file
# versionato copre sia il server di produzione sia la macchina di test.
#
# Porta locale: come cert e password, si CONSERVA quella gia' installata. Senza
# questo, rilanciare lo script per un altro motivo (es. rigenerare il cert) la
# riportava al default 1883 e su una macchina dove la 1883 e' del broker legacy
# mosquitto moriva con "Address already in use" — al riavvio successivo, ormai
# scollegato dal comando che l'aveva causato. LOCAL_PORT esplicito ha comunque
# la precedenza.
INSTALLED_CONF="$ETC/conf.d/c4rgo-scanner.conf"
if [[ -z "$LOCAL_PORT" && -f "$INSTALLED_CONF" ]]; then
  LOCAL_PORT="$(sed -n 's/^listener \([0-9]\+\) 127\.0\.0\.1$/\1/p' "$INSTALLED_CONF" | head -1)"
  [[ -n "$LOCAL_PORT" ]] && echo ">> Porta locale conservata da $INSTALLED_CONF: $LOCAL_PORT"
fi
LOCAL_PORT="${LOCAL_PORT:-1883}"

install -m 0644 "$HERE/../../docker/mqtt/acl" "$ETC/c4rgo-scanner.acl"
sed -e "s/my\.c4rgo\.cloud/$CN/g" \
    -e "s/^listener 1883 127\.0\.0\.1$/listener $LOCAL_PORT 127.0.0.1/" \
    "$HERE/mosquitto-c4rgo-scanner.conf" > "$ETC/conf.d/c4rgo-scanner.conf"
chmod 0644 "$ETC/conf.d/c4rgo-scanner.conf"

# 5) Utenti: r_server (worker) con password random stampata
if [[ ! -f "$ETC/c4rgo-scanner.passwd" ]]; then
  R_SERVER_PASS="$(openssl rand -base64 18)"
  mosquitto_passwd -b -c "$ETC/c4rgo-scanner.passwd" r_server "$R_SERVER_PASS"
  echo ">> Utente r_server creato. Metti QUESTA password in .env.local come"
  echo "   SCANNER_MQTT_PASSWORD (non salvata altrove, se la perdi rigenera):"
  echo "     r_server : $R_SERVER_PASS"
else
  echo ">> $ETC/c4rgo-scanner.passwd gia' presente: utenti non toccati."
fi
echo "   Aggiungi un utente per ogni device (username == device_id):"
echo "     sudo mosquitto_passwd -b $ETC/c4rgo-scanner.passwd kiosk_36b94b28 '<password>'"

# 6) permessi e restart
chown -R mosquitto:mosquitto "$CERTS" "$ETC/c4rgo-scanner.passwd" 2>/dev/null || true
chmod 600 "$CERTS/$CN.key" "$CERTS/ca.key" "$ETC/c4rgo-scanner.passwd"
systemctl enable mosquitto
systemctl restart mosquitto
echo ">> mosquitto riavviato. Verifica: journalctl -u mosquitto -n 30 --no-pager"
echo "   Deve aprire i listener 8883 (TLS) e $LOCAL_PORT (127.0.0.1)."
if [[ "$LOCAL_PORT" != "1883" ]]; then
  echo "   NB: porta locale $LOCAL_PORT -> metti SCANNER_MQTT_PORT=$LOCAL_PORT in .env.local"
fi
