(() => {
  const root = document.querySelector("[data-stream-testing]");
  if (!root) return;
  const player = root.querySelector("[data-stream-player]");
  const captions = root.querySelector("[data-stream-captions]");
  const empty = root.querySelector("[data-stream-empty]");
  const statePill = root.querySelector("[data-stream-state]");
  const summary = root.querySelector("[data-stream-summary]");
  const metrics = root.querySelector("[data-stream-metrics]");
  const warnings = root.querySelector("[data-stream-warnings]");
  const timeline = root.querySelector("[data-stream-timeline]");
  const advanced = root.querySelector("[data-stream-advanced]");
  const quality = root.querySelector("[data-stream-quality]");
  const fullscreen = root.querySelector("[data-stream-fullscreen]");
  const stop = root.querySelector("[data-stream-stop]");
  const pattern = root.querySelector("[data-stream-pattern]");
  let hls = null;
  let sessionId = null;

  const text = (value) => String(value ?? "");
  const html = (value) => text(value).replace(/[&<>"']/g, (character) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[character]);
  const metric = (label, value) => `<div><span>${html(label)}</span><strong>${html(value)}</strong></div>`;
  const bytes = (value) => {
    let size = Number(value) || 0;
    const units = ["B", "KB", "MB", "GB"];
    let unit = 0;
    while (size >= 1024 && unit < units.length - 1) { size /= 1024; unit += 1; }
    return `${size.toFixed(unit ? 1 : 0)} ${units[unit]}`;
  };

  function attach(session) {
    if (!session || sessionId === session.id) return;
    sessionId = session.id;
    hls?.destroy?.();
    hls = null;
    player.removeAttribute("src");
    const url = `${session.playback_url}?v=${encodeURIComponent(session.id)}`;
    captions.src = `${session.captions_url}?v=${encodeURIComponent(session.id)}`;
    if (window.Hls?.isSupported?.()) {
      hls = new window.Hls({ liveSyncDurationCount: 2, lowLatencyMode: false, xhrSetup: (xhr) => { xhr.withCredentials = true; } });
      hls.loadSource(url);
      hls.attachMedia(player);
      hls.on(window.Hls.Events.MANIFEST_PARSED, () => {
        quality.replaceChildren(new Option("Automatic", "-1"), ...hls.levels.map((level, index) => new Option(`${level.height || "Source"}p · ${Math.round((level.bitrate || 0) / 1000)} kbps`, String(index))));
        quality.disabled = false;
        player.play().catch(() => {});
      });
    } else if (player.canPlayType("application/vnd.apple.mpegurl")) {
      player.src = url;
    }
  }

  function detach() {
    sessionId = null;
    hls?.destroy?.();
    hls = null;
    player.pause();
    player.removeAttribute("src");
    captions.removeAttribute("src");
    player.load();
    quality.replaceChildren(new Option("Automatic", "-1"));
    quality.disabled = true;
  }

  function render(status) {
    const session = status.session;
    if (session) attach(session); else detach();
    if (session) captions.src = `${session.captions_url}?v=${encodeURIComponent(session.id)}&at=${Date.now()}`;
    statePill.textContent = session?.state || "Idle";
    statePill.className = `status-pill ${session?.state === "receiving" ? "success" : session ? "warning" : "neutral"}`;
    empty.hidden = Boolean(session);
    fullscreen.disabled = !session;
    stop.disabled = !session;
    pattern.disabled = Boolean(session);
    summary.innerHTML = [
      metric("Receiver", status.receiver.available ? "Ready" : "Needs setup"),
      metric("Session", session ? session.state : "No active test"),
      metric("Streaming computer", session?.device || "Not connected"),
      metric("Expires", session ? new Date(session.expires_at).toLocaleTimeString() : "—")
    ].join("");
    const obs = session?.metrics?.obs || {};
    const receiver = session?.metrics?.receiver || {};
    const captionMetrics = session?.metrics?.captions || {};
    const playerLatency = Number.isFinite(hls?.latency) ? `${hls.latency.toFixed(1)} s` : "Waiting";
    metrics.innerHTML = [
      metric("OBS bitrate", obs.bitrate_kbps ? `${Math.round(obs.bitrate_kbps)} kbps` : "Waiting"),
      metric("Dropped frames", `${obs.dropped_frames || 0} / ${obs.total_frames || 0}`),
      metric("OBS congestion", obs.congestion != null ? `${Math.round(obs.congestion * 100)}%` : "Waiting"),
      metric("Receiver speed", receiver.speed || "Waiting"),
      metric("Receiver FPS", receiver.fps || "Waiting"),
      metric("Player latency", playerLatency),
      metric("Caption delivery", captionMetrics.delivered ? `${captionMetrics.delivered} cues · ${Math.round(captionMetrics.last_delay_ms || 0)} ms last delay` : "Waiting"),
      metric("Temporary media", bytes(session?.metrics?.bytes))
    ].join("");
    warnings.replaceChildren(...(session?.warnings || (!status.receiver.available ? [{ severity: "critical", message: status.receiver.detail }] : [])).map((warning) => {
      const item = document.createElement("div");
      item.className = `callout ${warning.severity === "critical" ? "danger" : "warning"} stream-test-warning`;
      item.textContent = warning.message;
      return item;
    }));
    timeline.replaceChildren(...(status.timeline || []).slice().reverse().map((event) => {
      const item = document.createElement("li");
      item.textContent = `${new Date(event.at).toLocaleTimeString()} — ${event.message}`;
      return item;
    }));
    advanced.textContent = JSON.stringify({ receiver: status.receiver, source: session?.source, metrics: session?.metrics, ingest: session?.ingest }, null, 2);
  }

  async function refresh() {
    const response = await fetch("/admin/stream-testing/status", { cache: "no-store" });
    if (response.ok) render(await response.json());
  }
  quality.addEventListener("change", () => { if (hls) hls.currentLevel = Number(quality.value); });
  fullscreen.addEventListener("click", () => player.requestFullscreen?.());
  stop.addEventListener("click", async () => {
    if (!sessionId) return;
    stop.disabled = true;
    await fetch("/admin/stream-testing/stop", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ session_id: sessionId }) });
    await refresh();
  });
  pattern.addEventListener("click", async () => {
    pattern.disabled = true;
    const response = await fetch("/admin/stream-testing/pattern/start", { method: "POST", headers: { "Content-Type": "application/json" }, body: "{}" });
    if (!response.ok) {
      const payload = await response.json().catch(() => ({}));
      window.alert(payload.error || "The deterministic test pattern could not start.");
    }
    await refresh();
  });
  const events = new EventSource("/api/events");
  events.addEventListener("stream-test:changed", refresh);
  window.addEventListener("pagehide", () => { events.close(); hls?.destroy?.(); }, { once: true });
  refresh();
})();
