#!/usr/bin/with-contenv bashio
# ==============================================================================
# Busch-Radio Spotify Bridge – Startup-Script
#
# Startet:
#   1. Icecast2        – HTTP-Stream-Server
#   2. OAuth-Hilfe     – Einrichtungs-Assistent auf Port 5589
#   3. librespot       – Virtueller Spotify Connect-Empfänger (PCM auf stdout)
#   4. Silence-Injektor– Fügt Stille ein wenn Spotify pausiert (hält Stream aufrecht)
#   5. ffmpeg          – Kodiert PCM → MP3/AAC und schickt es als Icecast-Quelle
#
# Bei Absturz wird die komplette Pipeline nach 5 Sekunden neu gestartet.
# ==============================================================================

set -u

# ── Konfiguration lesen ───────────────────────────────────────────────────────
DEVICE_NAME=$(bashio::config 'device_name')
BITRATE=$(bashio::config 'bitrate')
STREAM_FORMAT=$(bashio::config 'stream_format')
STREAM_PORT=$(bashio::config 'stream_port')
STREAM_MOUNT=$(bashio::config 'stream_mount')
ICECAST_PASSWORD=$(bashio::config 'icecast_password')

# ── Format-spezifische Einstellungen ──────────────────────────────────────────
if [ "${STREAM_FORMAT}" = "aac" ]; then
    FFMPEG_CODEC="aac"
    FFMPEG_FORMAT="adts"
    ICECAST_MIME="audio/aac"
else
    FFMPEG_CODEC="libmp3lame"
    FFMPEG_FORMAT="mp3"
    ICECAST_MIME="audio/mpeg"
fi

bashio::log.info "╔══════════════════════════════════════════════╗"
bashio::log.info "║     Busch-Radio Spotify Bridge v1.0.11      ║"
bashio::log.info "╚══════════════════════════════════════════════╝"
bashio::log.info "Gerätename   : ${DEVICE_NAME}"
bashio::log.info "Bitrate      : ${BITRATE} kbps"
bashio::log.info "Format       : ${STREAM_FORMAT}"
bashio::log.info "Stream-Port  : ${STREAM_PORT}"
bashio::log.info "Stream-Pfad  : ${STREAM_MOUNT}"

# ── Verzeichnisse anlegen + Berechtigungen für nobody-User setzen ────────────
# Icecast läuft im Container als root, wechselt aber via changeowner zu nobody.
mkdir -p /var/log/icecast /run/icecast /tmp/busch-radio
chown -R nobody:nobody /var/log/icecast /run/icecast /tmp/busch-radio

# ── Icecast-Webroot ermitteln ─────────────────────────────────────────────────
# Alpine und Debian legen Icecast in unterschiedliche Pfade
ICECAST_WEBROOT=""
for candidate in /usr/share/icecast /usr/share/icecast2; do
    if [ -d "$candidate" ]; then
        ICECAST_WEBROOT="$candidate"
        break
    fi
done

if [ -z "$ICECAST_WEBROOT" ]; then
    bashio::log.warning "Icecast-Webroot nicht gefunden, verwende /usr/share/icecast"
    ICECAST_WEBROOT="/usr/share/icecast"
    mkdir -p "${ICECAST_WEBROOT}/web" "${ICECAST_WEBROOT}/admin"
fi

bashio::log.debug "Icecast-Webroot: ${ICECAST_WEBROOT}"

# ── Icecast-Konfiguration generieren ─────────────────────────────────────────
bashio::log.info "Icecast-Konfiguration wird erstellt..."

cat > /tmp/busch-radio/icecast.xml <<ICECAST_EOF
<icecast>
  <location>Home Assistant</location>
  <admin>admin@localhost</admin>

  <limits>
    <clients>10</clients>
    <sources>2</sources>
    <queue-size>524288</queue-size>
    <client-timeout>30</client-timeout>
    <header-timeout>15</header-timeout>
    <source-timeout>30</source-timeout>
    <burst-on-connect>0</burst-on-connect>
    <burst-size>65536</burst-size>
  </limits>

  <authentication>
    <source-password>${ICECAST_PASSWORD}</source-password>
    <relay-password>${ICECAST_PASSWORD}</relay-password>
    <admin-user>admin</admin-user>
    <admin-password>${ICECAST_PASSWORD}</admin-password>
  </authentication>

  <hostname>0.0.0.0</hostname>

  <listen-socket>
    <port>${STREAM_PORT}</port>
  </listen-socket>

  <mount>
    <mount-name>${STREAM_MOUNT}</mount-name>
    <public>0</public>
    <stream-name>Busch-Radio Spotify Bridge</stream-name>
    <stream-description>Spotify via Home Assistant</stream-description>
    <bitrate>${BITRATE}</bitrate>
    <type>${ICECAST_MIME}</type>
  </mount>

  <fileserve>1</fileserve>

  <paths>
    <basedir>${ICECAST_WEBROOT}</basedir>
    <logdir>/var/log/icecast</logdir>
    <webroot>${ICECAST_WEBROOT}/web</webroot>
    <adminroot>${ICECAST_WEBROOT}/admin</adminroot>
    <pidfile>/run/icecast/icecast.pid</pidfile>
  </paths>

  <logging>
    <!-- "-" loggt auf stderr → wird von HA erfasst -->
    <accesslog>-</accesslog>
    <errorlog>-</errorlog>
    <loglevel>2</loglevel>
    <logsize>10000</logsize>
  </logging>

  <security>
    <chroot>0</chroot>
    <!-- Icecast wechselt nach dem Start zu nobody – verhindert den root-Fehler -->
    <changeowner>
      <user>nobody</user>
      <group>nobody</group>
    </changeowner>
  </security>
</icecast>
ICECAST_EOF

# ── Icecast starten ───────────────────────────────────────────────────────────
bashio::log.info "Icecast wird gestartet (Port: ${STREAM_PORT})..."
icecast -c /tmp/busch-radio/icecast.xml &
ICECAST_PID=$!

# Kurz warten bis Icecast hochgefahren ist
sleep 3

if ! kill -0 "${ICECAST_PID}" 2>/dev/null; then
    bashio::log.fatal "Icecast konnte nicht gestartet werden! Prüfe die Konfiguration."
    exit 1
fi
bashio::log.info "Icecast läuft (PID: ${ICECAST_PID})"

# ── Credential-Cache-Verzeichnis ─────────────────────────────────────────────
# Credentials werden in /data gespeichert (persistentes Add-on Verzeichnis).
CREDENTIAL_CACHE="/data/librespot-cache"
mkdir -p "${CREDENTIAL_CACHE}"

# ── IP-Adresse des Hosts ermitteln ───────────────────────────────────────────
HA_IP=$(ip route get 1 2>/dev/null | awk '{for(i=1;i<=NF;i++) if($i=="src") print $(i+1)}' | head -1)
if [ -z "${HA_IP}" ]; then
    HA_IP=$(hostname -I 2>/dev/null | awk '{print $1}')
fi
if [ -z "${HA_IP}" ]; then
    HA_IP="<homeassistant-ip>"
fi

# ── OAuth-Hilfsserver starten ─────────────────────────────────────────────────
# Stellt unter http://<ha-ip>:5589 einen Einrichtungs-Assistenten bereit,
# der den Spotify-OAuth-Prozess Schritt für Schritt erklärt.
python3 /oauth_helper.py "${HA_IP}" &
OAUTH_HELPER_PID=$!
bashio::log.info "OAuth-Hilfsseite: http://${HA_IP}:5589"

# ── Librespot-Argumente zusammenstellen ───────────────────────────────────────
LIBRESPOT_ARGS=(
    "--name"              "${DEVICE_NAME}"
    "--bitrate"           "${BITRATE}"
    "--backend"           "pipe"
    "--device-type"       "computer"
    "--disable-audio-cache"
    "--initial-volume"    "100"
    "--disable-discovery"
    "--enable-oauth"
    "--system-cache"      "${CREDENTIAL_CACHE}"
)

# Prüfen ob bereits Credentials gecacht sind
if [ -f "${CREDENTIAL_CACHE}/credentials.json" ]; then
    bashio::log.info "Gespeicherte Credentials gefunden – Direktstart."
else
    bashio::log.info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    bashio::log.info "ERSTER START – Spotify-Autorisierung erforderlich!"
    bashio::log.info ""
    bashio::log.info "Öffne die Einrichtungs-Seite im Browser:"
    bashio::log.info "  http://${HA_IP}:5589"
    bashio::log.info ""
    bashio::log.info "Der Assistent führt dich durch die Anmeldung."
    bashio::log.info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
fi

# ── Icecast-Source-URL ────────────────────────────────────────────────────────
ICECAST_SOURCE_URL="icecast://source:${ICECAST_PASSWORD}@localhost:${STREAM_PORT}${STREAM_MOUNT}"

# ── Stream-URL ausgeben ───────────────────────────────────────────────────────
bashio::log.info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
bashio::log.info "Stream-URL für das Busch-Jäger Radio:"
bashio::log.info "  http://${HA_IP}:${STREAM_PORT}${STREAM_MOUNT}"
bashio::log.info ""
bashio::log.info "Icecast-Statusseite:"
bashio::log.info "  http://${HA_IP}:${STREAM_PORT}"
bashio::log.info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
bashio::log.info "Wähle '${DEVICE_NAME}' in der Spotify-App als Abspielgerät."
bashio::log.info "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

# ── Aufräumen bei SIGTERM ─────────────────────────────────────────────────────
cleanup() {
    bashio::log.info "Add-on wird beendet..."
    kill "${ICECAST_PID}" "${OAUTH_HELPER_PID}" 2>/dev/null || true
    exit 0
}
trap cleanup SIGTERM SIGINT

# ── Silence-Injektor ─────────────────────────────────────────────────────────
# Sitzt zwischen librespot und ffmpeg.
# Wenn Spotify pausiert, hört librespot auf zu schreiben. Ohne Injektor würde
# ffmpeg/Icecast den Stream nach einigen Sekunden Stille trennen.
# Der Injektor füllt die Pause mit Stille-Bytes, damit der Stream bestehen bleibt.
SILENCE_INJECTOR='
import sys, select, os
CHUNK = 8820  # 50 ms @ 44100 Hz, S16LE, Stereo (44100*2*2/20)
silence = bytes(CHUNK)
fd = sys.stdin.buffer.fileno()
while True:
    r, _, _ = select.select([fd], [], [], 0.05)
    if r:
        data = os.read(fd, CHUNK)
        if not data:
            break
        sys.stdout.buffer.write(data)
    else:
        sys.stdout.buffer.write(silence)
    sys.stdout.buffer.flush()
'

# ── Haupt-Schleife: Pipeline starten und bei Absturz neu starten ──────────────
#
# Signalfluss:
#   librespot (Spotify Connect) → stdout (raw PCM 44100Hz/S16LE/Stereo)
#                               ↓
#   silence-injector (Python)  → leitet durch; bei Pause: sendet Stille
#                               ↓
#   ffmpeg -re (Echtzeit)      → PCM → MP3/AAC Encoding → Icecast
#                                                           ↓
#                                          Busch-Jäger Radio (HTTP-Client)
#
# -re: Liest den Input in Echtzeit – verhindert zu schnelles Vorspulen
#      und gibt librespot korrekte Positions-Rückmeldung (Pause/Skip).
#
# Wenn entweder librespot oder ffmpeg abstürzt, wird die komplette Pipeline
# nach RESTART_DELAY Sekunden neu gestartet.
RESTART_DELAY=5
ATTEMPT=0

while true; do
    ATTEMPT=$((ATTEMPT + 1))
    bashio::log.info "Pipeline-Start (Versuch ${ATTEMPT})..."

    # Librespot stderr: Zeilen werden an HA-Log weitergeleitet UND auf
    # "Browse to:"-URL geprüft → wird in Datei für OAuth-Hilfsserver gespeichert.
    librespot "${LIBRESPOT_ARGS[@]}" \
        2> >(while IFS= read -r line; do
                echo "$line" >&2
                case "$line" in
                    *"Browse to:"*)
                        echo "$line" | sed 's/.*Browse to: //' | tr -d '\r\n ' \
                            > /tmp/busch-radio/auth_url.txt
                        bashio::log.info "Spotify-Anmeldung: http://${HA_IP}:5589 öffnen"
                        ;;
                esac
             done) \
        | python3 -c "${SILENCE_INJECTOR}" \
        | ffmpeg \
            -re \
            -hide_banner \
            -loglevel warning \
            -f s16le -ar 44100 -ac 2 \
            -i pipe:0 \
            -codec:a "${FFMPEG_CODEC}" \
            -b:a "${BITRATE}k" \
            -f "${FFMPEG_FORMAT}" \
            "${ICECAST_SOURCE_URL}" \
        || true

    # Auth-URL-Datei leeren damit die Hilfsseite beim Neustart wieder wartet
    rm -f /tmp/busch-radio/auth_url.txt

    bashio::log.warning "Pipeline beendet. Neustart in ${RESTART_DELAY}s..."
    sleep "${RESTART_DELAY}"
done
