#!/usr/bin/env bash
# ===========================================================================
#  TV-Wall - Installation auf dem Raspberry Pi (Raspberry Pi OS / Raspbian)
#
#  Aufruf:   sudo ./install.sh [Optionen]
#
#  Optionen:
#    --no-ap        WLAN-Access-Point nicht einrichten
#    --ap-only      nur den Access Point einrichten
#    --config PFAD  andere Konfigurationsdatei verwenden
#    --yes          keine Rueckfragen stellen
# ===========================================================================
set -euo pipefail

SRC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_DST="/etc/tvwall/tvwall.conf"
BIN_DST="/usr/local/bin/tvwall"
UNIT_DST="/etc/systemd/system/tvwall.service"
DOC_DST="/opt/tvwall"

WITH_AP=1
AP_ONLY=0
ASSUME_YES=0
CONFIG_SRC=""

info()  { printf '\033[1;36m==>\033[0m %s\n' "$*"; }
ok()    { printf '\033[1;32m  ✓\033[0m %s\n' "$*"; }
warn()  { printf '\033[1;33m  !\033[0m %s\n' "$*"; }
die()   { printf '\033[1;31mFehler:\033[0m %s\n' "$*" >&2; exit 1; }

while [[ $# -gt 0 ]]; do
  case "$1" in
    --no-ap)   WITH_AP=0; shift ;;
    --ap-only) AP_ONLY=1; shift ;;
    --yes|-y)  ASSUME_YES=1; shift ;;
    --config)  CONFIG_SRC="${2:-}"; shift 2 ;;
    -h|--help) sed -n '2,15p' "$0"; exit 0 ;;
    *)         die "unbekannte Option: $1" ;;
  esac
done

[[ $EUID -eq 0 ]] || die "bitte mit sudo starten:  sudo $0"

# ---------------------------------------------------------------------------
# Konfiguration einlesen
# ---------------------------------------------------------------------------
if [[ -z "$CONFIG_SRC" ]]; then
  if [[ -f "$CONFIG_DST" ]]; then
    CONFIG_SRC="$CONFIG_DST"          # bestehende Installation: nicht ueberschreiben
  else
    CONFIG_SRC="$SRC_DIR/config/tvwall.conf"
  fi
fi
[[ -f "$CONFIG_SRC" ]] || die "Konfigurationsdatei nicht gefunden: $CONFIG_SRC"

set -a
# shellcheck disable=SC1090
. "$CONFIG_SRC"
set +a

AP_SSID="${AP_SSID:-TVWall-01}"
RUN_USER="${RUN_USER:-tvwall}"
STATE_DIR="${STATE_DIR:-/var/lib/tvwall}"
DISPLAY_MODE="${DISPLAY_MODE:-auto}"
HOSTNAME_NEW="${HOSTNAME:-tvwall-01}"
WEB_PORT="${WEB_PORT:-80}"

# --- Bildausgabe bestimmen --------------------------------------------------
# Der Desktop-Benutzer ist der einzige, der an die Sitzung herankommt.
detect_desktop_user() {
  local d u
  for d in /run/user/*; do
    [[ -d "$d" ]] || continue
    compgen -G "$d/wayland-*" >/dev/null 2>&1 || continue
    u="$(getent passwd "$(basename "$d")" | cut -d: -f1)"
    [[ -n "$u" ]] && { echo "$u"; return; }
  done
  u="$(sed -n 's/^autologin-user=//p' /etc/lightdm/lightdm.conf 2>/dev/null | head -1)"
  [[ -n "$u" ]] && { echo "$u"; return; }
  u="$(sed -n 's/.*--autologin \([^ ]*\).*/\1/p' \
       /etc/systemd/system/getty@tty1.service.d/autologin.conf 2>/dev/null | head -1)"
  [[ -n "$u" && "$u" != "root" ]] && { echo "$u"; return; }
  getent passwd 1000 | cut -d: -f1
}

GRAPHICAL=0
[[ "$(systemctl get-default 2>/dev/null)" == "graphical.target" ]] && GRAPHICAL=1
pgrep -x labwc  >/dev/null 2>&1 && GRAPHICAL=1
pgrep -x wayfire >/dev/null 2>&1 && GRAPHICAL=1
pgrep -x Xorg   >/dev/null 2>&1 && GRAPHICAL=1

DISPLAY_MODE_CHANGED=0
# Eine bestehende Konfiguration wird nicht ueberschrieben - deshalb kann hier
# noch ein "drm" aus einer frueheren Installation stehen. Auf einem System mit
# Desktop fuehrt das zwangslaeufig zum schwarzen Bildschirm.
if [[ "$DISPLAY_MODE" == "drm" && $GRAPHICAL -eq 1 ]]; then
  echo
  warn "In der Konfiguration steht DISPLAY_MODE=\"drm\", auf diesem Pi laeuft aber"
  warn "ein Desktop. mpv kann den Bildschirm so nicht bekommen - er bliebe schwarz."
  if [[ $ASSUME_YES -eq 1 ]]; then
    DISPLAY_MODE="auto"; DISPLAY_MODE_CHANGED=1
  else
    read -r -p "    Auf DISPLAY_MODE=\"auto\" umstellen? [J/n] " answer
    if [[ ! "$answer" =~ ^[nN]$ ]]; then
      DISPLAY_MODE="auto"; DISPLAY_MODE_CHANGED=1
    fi
  fi
  echo
fi

EFFECTIVE_MODE="$DISPLAY_MODE"
if [[ "$EFFECTIVE_MODE" == "auto" ]]; then
  if [[ $GRAPHICAL -eq 1 ]]; then
    EFFECTIVE_MODE="desktop"
  else
    EFFECTIVE_MODE="drm"
  fi
fi

RUN_USER_CHANGED=0
if [[ "$EFFECTIVE_MODE" == "desktop" && "$RUN_USER" == "tvwall" ]]; then
  DESKTOP_USER="$(detect_desktop_user || true)"
  if [[ -n "$DESKTOP_USER" ]]; then
    RUN_USER="$DESKTOP_USER"
    RUN_USER_CHANGED=1
  fi
fi

info "Konfiguration: $CONFIG_SRC"
echo "    WLAN-Name (SSID) : $AP_SSID"
echo "    Hostname         : $HOSTNAME_NEW"
if [[ "$DISPLAY_MODE" == "auto" ]]; then
  echo "    Bildausgabe      : auto -> $EFFECTIVE_MODE"
else
  echo "    Bildausgabe      : $EFFECTIVE_MODE"
fi
if [[ $RUN_USER_CHANGED -eq 1 ]]; then
  echo "    Benutzer         : $RUN_USER   (Desktop-Benutzer, automatisch erkannt)"
else
  echo "    Benutzer         : $RUN_USER"
fi
echo "    Medienordner     : $STATE_DIR/media"
echo

if [[ $AP_ONLY -eq 1 ]]; then
  exec "$SRC_DIR/scripts/setup-ap.sh" "$CONFIG_SRC"
fi

# ---------------------------------------------------------------------------
# Pakete
# ---------------------------------------------------------------------------
if command -v apt-get >/dev/null; then
  MISSING=()
  command -v mpv    >/dev/null || MISSING+=(mpv)
  command -v ffmpeg >/dev/null || MISSING+=(ffmpeg)
  if [[ ${#MISSING[@]} -gt 0 ]]; then
    info "Installiere Pakete: ${MISSING[*]}"
    DEBIAN_FRONTEND=noninteractive apt-get update -qq
    DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "${MISSING[@]}"
  fi
  ok "mpv und ffmpeg vorhanden"
else
  warn "kein apt-get gefunden - mpv und ffmpeg bitte selbst installieren"
fi

# ---------------------------------------------------------------------------
# Programm installieren
# ---------------------------------------------------------------------------
info "Installiere Programm nach $BIN_DST"
ARCH="$(uname -m)"
case "$ARCH" in
  aarch64|arm64) PREBUILT="$SRC_DIR/build/tvwall-linux-arm64" ;;
  armv7l|armv6l) PREBUILT="$SRC_DIR/build/tvwall-linux-arm" ;;
  x86_64)        PREBUILT="$SRC_DIR/build/tvwall-linux-amd64" ;;
  *)             PREBUILT="" ;;
esac

if [[ -n "$PREBUILT" && -f "$PREBUILT" ]]; then
  install -m 0755 "$PREBUILT" "$BIN_DST"
  ok "fertiges Programm verwendet ($ARCH)"
elif command -v go >/dev/null && [[ -f "$SRC_DIR/go.mod" ]]; then
  info "Baue aus dem Quelltext (das dauert einen Moment)"
  ( cd "$SRC_DIR" && go build -trimpath -ldflags "-s -w" -o /tmp/tvwall.build ./cmd/tvwall )
  install -m 0755 /tmp/tvwall.build "$BIN_DST" && rm -f /tmp/tvwall.build
  ok "aus Quelltext gebaut"
elif [[ -x "$BIN_DST" ]]; then
  # Erneuter Aufruf aus /opt/tvwall, nur um die Konfiguration zu uebernehmen.
  ok "vorhandenes Programm beibehalten ($("$BIN_DST" -version 2>/dev/null || echo unbekannt))"
else
  die "kein passendes Programm gefunden ($ARCH) und Go ist nicht installiert.
       Auf dem Entwicklungsrechner 'make dist' ausfuehren und das Paket hierher kopieren."
fi

# ---------------------------------------------------------------------------
# Benutzer und Verzeichnisse
# ---------------------------------------------------------------------------
if ! id -u "$RUN_USER" >/dev/null 2>&1; then
  info "Lege Benutzer $RUN_USER an"
  useradd --system --create-home --home-dir "/home/$RUN_USER" --shell /usr/sbin/nologin "$RUN_USER"
fi
for grp in video render audio input tty; do
  getent group "$grp" >/dev/null && usermod -aG "$grp" "$RUN_USER" || true
done
ok "Benutzer $RUN_USER eingerichtet"

install -d -m 0775 -o "$RUN_USER" -g "$RUN_USER" "$STATE_DIR" "$STATE_DIR/media" "$STATE_DIR/thumbs"
chown -R "$RUN_USER":"$RUN_USER" "$STATE_DIR" 2>/dev/null || true
ok "Medienordner: $STATE_DIR/media"

install -d -m 0755 /etc/tvwall
if [[ -f "$CONFIG_DST" && "$CONFIG_SRC" != "$CONFIG_DST" ]]; then
  install -m 0644 "$CONFIG_SRC" "$CONFIG_DST.neu"
  warn "$CONFIG_DST existiert bereits - neue Fassung liegt als $CONFIG_DST.neu daneben"
elif [[ ! -f "$CONFIG_DST" ]]; then
  install -m 0644 "$CONFIG_SRC" "$CONFIG_DST"
  ok "Konfiguration nach $CONFIG_DST kopiert"
fi

if [[ $RUN_USER_CHANGED -eq 1 && -f "$CONFIG_DST" ]]; then
  sed -i "s|^RUN_USER=.*|RUN_USER=\"$RUN_USER\"|" "$CONFIG_DST"
  ok "RUN_USER in $CONFIG_DST auf '$RUN_USER' gesetzt (Desktop-Benutzer)"
fi
if [[ $DISPLAY_MODE_CHANGED -eq 1 && -f "$CONFIG_DST" ]]; then
  sed -i "s|^DISPLAY_MODE=.*|DISPLAY_MODE=\"auto\"|" "$CONFIG_DST"
  ok "DISPLAY_MODE in $CONFIG_DST auf 'auto' gesetzt"
fi

install -d -m 0755 "$DOC_DST"
[[ -f "$SRC_DIR/README.md" ]] && install -m 0644 "$SRC_DIR/README.md" "$DOC_DST/README.md"
if [[ -d "$SRC_DIR/scripts" ]]; then
  install -d -m 0755 "$DOC_DST/scripts"
  install -m 0755 "$SRC_DIR"/scripts/* "$DOC_DST/scripts/"
fi
# Installer und Vorlagen mitnehmen, damit spaetere Aenderungen ohne das
# Quellpaket auskommen:  sudo /opt/tvwall/install.sh --no-ap
if [[ "$SRC_DIR" != "$DOC_DST" ]]; then
  install -m 0755 "$SRC_DIR/install.sh" "$DOC_DST/install.sh"
  install -d -m 0755 "$DOC_DST/systemd" "$DOC_DST/config"
  install -m 0644 "$SRC_DIR"/systemd/*.in "$DOC_DST/systemd/"
  install -m 0644 "$SRC_DIR"/config/tvwall.conf "$DOC_DST/config/tvwall.conf"
fi

# ---------------------------------------------------------------------------
# systemd-Dienst
# ---------------------------------------------------------------------------
info "Richte systemd-Dienst ein"
if [[ "$EFFECTIVE_MODE" == "desktop" ]]; then
  TEMPLATE="$SRC_DIR/systemd/tvwall-desktop.service.in"
  RUN_UID="$(id -u "$RUN_USER")"
  if [[ "$RUN_USER" == "tvwall" ]]; then
    warn "Bildausgabe im Desktop, aber der Dienst laeuft als 'tvwall'."
    warn "Nur der Benutzer, dem die Desktop-Sitzung gehoert, kommt an den Bildschirm."
    warn "Bitte RUN_USER in $CONFIG_DST auf den Desktop-Benutzer setzen (meist 'pi')."
  fi
else
  TEMPLATE="$SRC_DIR/systemd/tvwall-drm.service.in"
  RUN_UID=""
fi
[[ -f "$TEMPLATE" ]] || die "Vorlage fehlt: $TEMPLATE"

sed -e "s|@RUN_USER@|$RUN_USER|g" \
    -e "s|@RUN_UID@|$RUN_UID|g" \
    -e "s|@CONFIG@|$CONFIG_DST|g" \
    "$TEMPLATE" > "$UNIT_DST"
chmod 0644 "$UNIT_DST"

if [[ "$EFFECTIVE_MODE" != "desktop" ]]; then
  # Auf der Konsole soll kein Login-Prompt um den Bildschirm streiten.
  systemctl disable --now getty@tty1.service >/dev/null 2>&1 || true
else
  # Im Desktop-Betrieb wird tty1 gebraucht - eine frueher im Konsolenmodus
  # abgeschaltete Konsole hier wieder einschalten.
  if ! systemctl is-enabled --quiet getty@tty1.service 2>/dev/null; then
    systemctl enable --now getty@tty1.service >/dev/null 2>&1 || true
    ok "Konsole auf tty1 wieder aktiviert"
  fi
fi

systemctl daemon-reload
systemctl enable tvwall.service >/dev/null
ok "Dienst aktiviert (startet ab jetzt bei jedem Einschalten mit)"

# ---------------------------------------------------------------------------
# Hostname
# ---------------------------------------------------------------------------
if [[ -n "$HOSTNAME_NEW" && "$(hostname)" != "$HOSTNAME_NEW" ]]; then
  info "Setze Hostname auf $HOSTNAME_NEW"
  hostnamectl set-hostname "$HOSTNAME_NEW" || true
  sed -i "s/^127\.0\.1\.1.*/127.0.1.1\t$HOSTNAME_NEW/" /etc/hosts 2>/dev/null || true
  grep -q "^127.0.1.1" /etc/hosts || printf '127.0.1.1\t%s\n' "$HOSTNAME_NEW" >> /etc/hosts
fi
command -v avahi-daemon >/dev/null && systemctl enable --now avahi-daemon >/dev/null 2>&1 || true

# ---------------------------------------------------------------------------
# Access Point
# ---------------------------------------------------------------------------
if [[ $WITH_AP -eq 1 ]]; then
  if [[ $ASSUME_YES -eq 0 ]]; then
    echo
    warn "Der Access Point belegt das WLAN des Pi."
    warn "Bist du gerade per WLAN verbunden, bricht diese Verbindung ab."
    read -r -p "    Access Point '$AP_SSID' jetzt einrichten? [j/N] " answer
    [[ "$answer" =~ ^[jJyY]$ ]] || WITH_AP=0
  fi
fi
if [[ $WITH_AP -eq 1 ]]; then
  "$SRC_DIR/scripts/setup-ap.sh" "$CONFIG_DST" || warn "Access Point konnte nicht eingerichtet werden - siehe Meldungen oben"
else
  info "Access Point uebersprungen (spaeter: sudo $DOC_DST/scripts/setup-ap.sh)"
fi

# ---------------------------------------------------------------------------
# Start
# ---------------------------------------------------------------------------
info "Starte Dienst"
systemctl restart tvwall.service
sleep 2
if systemctl is-active --quiet tvwall.service; then
  ok "tvwall laeuft"
else
  warn "Dienst laeuft nicht - Protokoll ansehen mit:  journalctl -u tvwall -n 50"
fi

PORT_SUFFIX=""
[[ "$WEB_PORT" != "80" ]] && PORT_SUFFIX=":$WEB_PORT"
cat <<EOF

===========================================================================
 Fertig.

   WLAN verbinden mit :  $AP_SSID
   Webinterface       :  http://${AP_IP:-192.168.4.1}$PORT_SUFFIX
                         http://$HOSTNAME_NEW.local$PORT_SUFFIX
   Medienordner       :  $STATE_DIR/media

   Protokoll ansehen  :  journalctl -u tvwall -f
   Dienst neu starten :  sudo systemctl restart tvwall
   Konfiguration      :  sudo nano $CONFIG_DST
===========================================================================
EOF
