#!/usr/bin/env bash
# ===========================================================================
#  Findet heraus, WELCHE mpv-Option (oder welcher Ablauf) einen Haenger
#  ausloest. Statt zu raten wird jede Variante gemessen.
#
#  Aufruf:  sudo /opt/tvwall/scripts/bisect-mpv.sh /var/lib/tvwall/media/<video>
#
#  Der Bildschirm flackert waehrenddessen - das ist normal, jede Variante
#  spielt acht Sekunden. Der Dienst wird angehalten und danach neu gestartet.
# ===========================================================================
set -uo pipefail

CONF="/etc/tvwall/tvwall.conf"
LIMIT=25          # Sekunden, nach denen eine Variante als "haengt" gilt
PLAYSEC=8         # so lange soll jede Variante spielen

hdr()  { printf '\n\033[1;36m── %s ──────────────────────────\033[0m\n' "$*"; }
ok()   { printf '  \033[1;32mLAEUFT\033[0m  %-46s %ss\n' "$1" "$2"; }
bad()  { printf '  \033[1;31mHAENGT\033[0m  %-46s Abbruch nach %ss\n' "$1" "$2"; }
odd()  { printf '  \033[1;33mFEHLER\033[0m  %-46s Code %s\n' "$1" "$2"; }
note() { printf '    %s\n' "$*"; }
die()  { printf '\033[1;31mFehler:\033[0m %s\n' "$*" >&2; exit 1; }

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

VIDEO="${1:-}"
[[ -n "$VIDEO" && -f "$VIDEO" ]] || die "Bitte eine Videodatei angeben:
       sudo $0 /var/lib/tvwall/media/<datei>.mp4"

RUN_USER="tvwall"; STATE_DIR="/var/lib/tvwall"; DISPLAY_MODE="auto"
[[ -f "$CONF" ]] && { set -a; . "$CONF" 2>/dev/null; set +a; }
RUN_USER="${RUN_USER:-tvwall}"; STATE_DIR="${STATE_DIR:-/var/lib/tvwall}"
RUN_UID="$(id -u "$RUN_USER" 2>/dev/null)" || die "Benutzer $RUN_USER gibt es nicht"

# --- Umgebung wie beim Dienst ---------------------------------------------
ENV_ARGS=(XDG_RUNTIME_DIR="/run/user/$RUN_UID")
VO_ARGS=(--vo=gpu)
if ! ls "/run/user/$RUN_UID"/wayland-* >/dev/null 2>&1 && [[ -z "${DISPLAY:-}" ]]; then
  VO_ARGS=(--vo=gpu --gpu-context=drm)      # kein Desktop -> direkt auf den Schirm
fi

# Die Optionen, die der Dienst setzt (ohne --idle/--loop, sonst endet nichts).
SERVICE_ARGS=(
  --fullscreen --force-window=yes --keep-open=no
  --image-display-duration=2
  --no-osc --osd-level=0 --cursor-autohide=always
  --no-input-default-bindings --input-vo-keyboard=no
  --stop-screensaver=yes --no-input-terminal
  "${VO_ARGS[@]}"
)

# --- Testmaterial ----------------------------------------------------------
IMAGE="$(find "$STATE_DIR/media" -maxdepth 1 -type f \
         \( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' \) | sort | head -1)"
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
printf '%s\n' "$VIDEO" > "$TMP/nur-video.m3u"
if [[ -n "$IMAGE" ]]; then
  printf '%s\n%s\n' "$IMAGE" "$VIDEO" > "$TMP/bild-video.m3u"
fi
chmod -R a+rX "$TMP"

LOGDIR="$TMP/logs"; mkdir -p "$LOGDIR"
FAILED=()
declare -A RESULT

# Ein Durchlauf. LEN=0 laesst die Datei komplett laufen (ohne --length).
attempt() {
  local log="$1" limit="$2" len="$3"; shift 3
  local extra=()
  [[ "$len" != "0" ]] && extra=(--length="$len")
  sudo -u "$RUN_USER" env "${ENV_ARGS[@]}" \
    timeout -k 3 "$limit" mpv --no-config --msg-level=all=error "${extra[@]}" "$@" \
    >"$log" 2>&1
}

run_as() {
  local id="$1" label="$2" limit="$3" len="$4"; shift 4
  local log="$LOGDIR/$id.log"
  local start rc dur
  start=$(date +%s)
  attempt "$log" "$limit" "$len" "$@"
  rc=$?
  dur=$(( $(date +%s) - start ))

  # Fehlschlaege einmal wiederholen: der Compositor verweigert zwischen zwei
  # Laeufen gelegentlich kurz die Verbindung - das ist kein echter Befund.
  if [[ $rc -ne 0 ]]; then
    sleep 3
    attempt "$log" "$limit" "$len" "$@"
    local rc2=$?
    if [[ $rc2 -eq 0 ]]; then
      RESULT[$id]=ok
      printf '  \033[1;32mLAEUFT\033[0m  %-46s %ss (erster Versuch einmalig gescheitert)\n' "$id  $label" "$dur"
      return
    fi
    rc=$rc2
  fi

  case $rc in
    0)       RESULT[$id]=ok;   ok  "$id  $label" "$dur" ;;
    124|137) RESULT[$id]=hang; bad "$id  $label" "$dur"; FAILED+=("$id  $label|$log") ;;
    *)       RESULT[$id]=err;  odd "$id  $label" "$rc";  FAILED+=("$id  $label|$log") ;;
  esac
  sleep 2
}

run() { run_as "$1" "$2" "$LIMIT" "$PLAYSEC" "${@:3}"; }

hdr "Vorbereitung"
note "Datei:    $(basename "$VIDEO")"
note "Benutzer: $RUN_USER (uid $RUN_UID)"
note "Ausgabe:  ${VO_ARGS[*]}"
[[ -n "$IMAGE" ]] && note "Bild:     $(basename "$IMAGE")" || note "Bild:     keines gefunden - Uebergangstest entfaellt"
systemctl stop tvwall 2>/dev/null && note "Dienst angehalten"
sleep 1

hdr "Ist die Datei ueberhaupt vollstaendig?"
if command -v ffmpeg >/dev/null; then
  FFOUT="$(ffmpeg -v error -i "$VIDEO" -f null - 2>&1)"
  if [[ -z "$FFOUT" ]]; then
    printf '  \033[1;32mIN ORDNUNG\033[0m  komplett dekodierbar\n'
  else
    printf '  \033[1;31mBESCHAEDIGT\033[0m  ffmpeg meldet beim Durchlesen:\n'
    echo "$FFOUT" | head -6 | sed 's/^/      /'
    note "-> Dann hilft kein Einstellen: die Datei bitte neu hochladen."
  fi
  note "Groesse: $(stat -c %s "$VIDEO" 2>/dev/null) Bytes, md5: $(md5sum "$VIDEO" | cut -d" " -f1)"
fi

hdr "Einzeldatei"
run 1 "nur --fullscreen (mpv-Standard)"          --fullscreen "$VIDEO"
run 2 "Dienst-Optionen"                          "${SERVICE_ARGS[@]}" "$VIDEO"
run 3 "Dienst-Optionen + --hwdec=auto-safe"      "${SERVICE_ARGS[@]}" --hwdec=auto-safe "$VIDEO"
run 4 "Dienst-Optionen + --no-audio"             "${SERVICE_ARGS[@]}" --no-audio "$VIDEO"
run 5 "Dienst-Optionen + --vo=gpu-next"          "${SERVICE_ARGS[@]/--vo=gpu/--vo=gpu-next}" "$VIDEO"

hdr "Als Playliste (so macht es der Dienst)"
run 6 "Playliste mit nur dem Video"              "${SERVICE_ARGS[@]}" --playlist="$TMP/nur-video.m3u"
if [[ -n "$IMAGE" ]]; then
  run 7 "Playliste Bild -> Video"                "${SERVICE_ARGS[@]}" --playlist="$TMP/bild-video.m3u"
  run 8 "Bild -> Video, ohne --force-window"     "${SERVICE_ARGS[@]/--force-window=yes/--force-window=no}" \
                                                 --playlist="$TMP/bild-video.m3u"
  run 9 "Bild -> Video, mit --gpu-context=auto"  "${SERVICE_ARGS[@]}" --gpu-context=auto \
                                                 --playlist="$TMP/bild-video.m3u"
  # Ohne --length, damit ausgeschlossen ist, dass diese Testoption stoert.
  run_as 10 "Bild -> Video, komplett bis zum Ende" 120 0 \
            "${SERVICE_ARGS[@]}" --playlist="$TMP/bild-video.m3u"
fi

hdr "Ergebnis"
r() { echo "${RESULT[$1]:-}"; }

if [[ ${#FAILED[@]} -gt 0 ]]; then
  note "Haengen geblieben:"
  for entry in "${FAILED[@]}"; do
    printf '      %s\n' "${entry%%|*}"
    tail -5 "${entry##*|}" 2>/dev/null | sed 's/^/          /'
  done
  echo
fi

note "Deutung:"
if [[ "$(r 1)" != "ok" ]]; then
  note "  Schon der nackte mpv-Aufruf haengt. Dann liegt es an der Datei oder"
  note "  am Grafiktreiber, nicht an den Einstellungen dieses Werkzeugs."
elif [[ "$(r 2)" != "ok" ]]; then
  note "  Der nackte Aufruf laeuft, die Dienst-Optionen nicht. Die Varianten 3-5"
  note "  zeigen, welche Option es ist."
elif [[ -n "$IMAGE" && "$(r 7)" != "ok" && "$(r 6)" == "ok" ]]; then
  note "  Die Einzeldatei laeuft, der Wechsel Bild -> Video nicht."
  if [[ "$(r 10)" == "ok" ]]; then
    note "  Variante 10 (ohne --length) laeuft aber durch - dann stoert nur die"
    note "  Testoption --length, und der Dienst selbst ist nicht betroffen."
  else
    note "  Auch ohne Testoptionen (Variante 10) scheitert es - echter Befund."
    note "  Meldet ffmpeg oben \"BESCHAEDIGT\", ist die Datei die Ursache."
  fi
  [[ "$(r 8)" == "ok" ]] && note "  --force-window=no behebt es -> genau das laesst sich einstellen."
  [[ "$(r 9)" == "ok" ]] && note "  --gpu-context=auto behebt es -> genau das laesst sich einstellen."
elif [[ ${#FAILED[@]} -eq 0 ]]; then
  note "  Keine Variante haengt. Dann liegt es nicht an mpv, sondern am"
  note "  Zusammenspiel mit dem Dienst - bitte 'journalctl -u tvwall -n 60' schicken."
fi

systemctl start tvwall 2>/dev/null
hdr "Dienst wieder gestartet"
