/* ========================================================================
   LUMINA — Floating Playlist Panel (dual: Audio + Visual)
   Two parallel queues running independently. Drop any file — routed to
   the right queue automatically.
   ======================================================================== */
(function () {
  const { useState, useEffect, useRef } = React;

  function PlaylistPanel() {
    const [open, setOpen] = useState(false);
    const [, tick] = useState(0);
    const [pos, setPos] = useState({ x: 24, y: 100 });
    const aInputRef = useRef(null);
    const vInputRef = useRef(null);
    const dragIdx = useRef({ pane: null, i: null });

    useEffect(() => {
      const id = setInterval(() => tick(n => n + 1), 250);
      const ua = window.AudioEngine?.onChange?.(() => tick(n => n + 1));
      const um = window.MediaStore?.on?.(() => tick(n => n + 1));
      const uv = window.VisualPlayer?.on?.(() => tick(n => n + 1));
      return () => { clearInterval(id); ua?.(); um?.(); uv?.(); };
    }, []);

    const E = window.AudioEngine;
    const V = window.VisualPlayer;
    const M = window.MediaStore;
    if (!E || !V) return null;

    const startDrag = (e) => {
      if (["BUTTON","INPUT","SELECT","TEXTAREA"].includes(e.target.tagName)) return;
      const start = { x: e.clientX, y: e.clientY };
      const sp = { ...pos };
      const onMove = (m) => setPos({ x: sp.x + (m.clientX - start.x), y: sp.y + (m.clientY - start.y) });
      const onUp = () => { window.removeEventListener("mousemove", onMove); window.removeEventListener("mouseup", onUp); };
      window.addEventListener("mousemove", onMove);
      window.addEventListener("mouseup", onUp);
    };

    const onAudioFiles = async (e) => {
      await E.addManyToQueue(Array.from(e.target.files));
      if (E.queue.length && !E.audioEl) E.playFromQueue(0);
      e.target.value = "";
    };
    const onVisualFiles = async (e) => {
      for (const f of e.target.files) {
        const layer = await M.add(f);
        if (layer) V.add(layer.id);
      }
      e.target.value = "";
    };
    const onDrop = async (e) => {
      e.preventDefault();
      const files = Array.from(e.dataTransfer.files);
      for (const f of files) {
        if (f.type.startsWith("audio")) {
          await E.addToQueue(f);
          if (!E.audioEl) E.playFromQueue(E.queue.length - 1);
        } else if (f.type.startsWith("image") || f.type.startsWith("video")) {
          const layer = await M.add(f);
          if (layer) V.add(layer.id);
        }
      }
    };

    /* drag-reorder */
    const onItemDragStart = (pane, i) => (e) => {
      dragIdx.current = { pane, i };
      e.dataTransfer.effectAllowed = "move";
      e.dataTransfer.setData("text/plain", `${pane}-${i}`);
    };
    const onItemDragOver = (e) => e.preventDefault();
    const onItemDrop = (pane, i) => (e) => {
      e.preventDefault();
      const d = dragIdx.current;
      if (d.pane !== pane || d.i == null || d.i === i) return;
      if (pane === "audio") E.moveInQueue(d.i, i);
      else V.move(d.i, i);
      dragIdx.current = { pane: null, i: null };
    };

    if (!open) {
      const total = E.queue.length + V.queue.length;
      return (
        <button
          onClick={() => setOpen(true)}
          style={{
            position: "fixed", left: 18, bottom: 110, zIndex: 595,
            padding: "10px 14px", border: "none", borderRadius: 8,
            background: total
              ? "radial-gradient(circle at 50% 0%, #c7f8ff 0%, #4be6ff 40%, #1880a0 100%)"
              : "linear-gradient(180deg, var(--panel-hi), var(--panel))",
            color: total ? "#062028" : "var(--ink-dim)",
            fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 11,
            letterSpacing: "0.18em", textTransform: "uppercase",
            cursor: "pointer",
            boxShadow: total
              ? "inset 0 1px 0 rgba(255,255,255,0.4), 0 0 14px rgba(75,230,255,0.5)"
              : "var(--nshadow-out-sm)",
            display: "flex", alignItems: "center", gap: 8,
          }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
            <path d="M3 4h14v2H3zM3 9h14v2H3zM3 14h10v2H3zM16 13l5 4-5 4z"/>
          </svg>
          Playlist {total ? `· ${E.queue.length}♪ + ${V.queue.length}▣` : ""}
        </button>
      );
    }

    const curA = E.queue[E.queueIdx];
    const visualLayer = V.queue[V.idx] ? M.layers.find(l => l.id === V.queue[V.idx]) : null;

    return (
      <div
        onDragOver={(e) => e.preventDefault()}
        onDrop={onDrop}
        style={{
          position: "fixed", left: pos.x, top: pos.y,
          width: 560, maxHeight: "82vh", zIndex: 595,
          background: "linear-gradient(180deg, var(--panel-hi), var(--panel-lo))",
          borderRadius: 10,
          boxShadow: "0 20px 50px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.06)",
          display: "flex", flexDirection: "column",
          overflow: "hidden",
        }}>
        {/* Header */}
        <div onMouseDown={startDrag} style={{
          padding: "10px 14px",
          display: "flex", alignItems: "center", gap: 8,
          cursor: "move", userSelect: "none",
          borderBottom: "1px solid rgba(255,255,255,0.06)",
          background: "linear-gradient(180deg, rgba(75,230,255,0.08), transparent)",
        }}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="var(--led-cyan)"
            style={{ filter: "drop-shadow(0 0 4px var(--led-cyan-glow))" }}>
            <path d="M3 4h14v2H3zM3 9h14v2H3zM3 14h10v2H3zM16 13l5 4-5 4z"/>
          </svg>
          <span style={{ flex: 1, fontFamily: "var(--font-display)", fontWeight: 800, fontSize: 12,
            letterSpacing: "0.16em", textTransform: "uppercase", color: "var(--led-cyan)",
            textShadow: "0 0 4px var(--led-cyan-glow)" }}>
            Playlist · Audio + Visual (parallel)
          </span>
          <button data-lum-close="1" className="nbtn compact" onClick={() => setOpen(false)} style={{ padding: "3px 8px" }}>×</button>
        </div>

        {/* Body: two columns */}
        <div style={{
          display: "grid", gridTemplateColumns: "1fr 1fr", flex: 1, minHeight: 0,
        }}>
          {/* === AUDIO COLUMN === */}
          <div style={{
            display: "flex", flexDirection: "column", minHeight: 0,
            borderRight: "1px solid rgba(255,255,255,0.06)",
          }}>
            {/* Audio Now Playing */}
            <div style={{ padding: 10, background: "rgba(0,0,0,0.2)",
              borderBottom: "1px solid rgba(255,255,255,0.04)" }}>
              <div className="cap" style={{ fontSize: 8, display: "flex", justifyContent: "space-between" }}>
                <span>♪ Audio Queue</span>
                <span style={{ color: "var(--accent)" }}>{E.queue.length}</span>
              </div>
              <div style={{
                fontFamily: "var(--font-mono)", fontSize: 10, color: curA ? "var(--accent)" : "var(--ink-faint)",
                textShadow: curA ? "0 0 4px var(--accent-glow)" : "none",
                whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", marginTop: 4,
              }}>
                {curA ? `${E.queueIdx + 1}. ${curA.name}` : "— empty —"}
              </div>
              <div style={{ display: "flex", gap: 4, marginTop: 6 }}>
                <button className="nbtn compact" onClick={() => E.prevTrack()} disabled={!E.queue.length}
                  style={{ padding: "3px 5px", fontSize: 9 }}>◀◀</button>
                <button className="nbtn compact" style={{ flex: 1, padding: "3px 5px", fontSize: 9 }}
                  onClick={() => E.audioEl?.paused ? E.audioEl.play() : E.audioEl?.pause()}>
                  {E.audioEl && !E.audioEl.paused ? "❚❚" : "▶"}
                </button>
                <button className="nbtn compact" onClick={() => E.nextTrack()} disabled={!E.queue.length}
                  style={{ padding: "3px 5px", fontSize: 9 }}>▶▶</button>
              </div>
              <div style={{ display: "flex", gap: 4, marginTop: 4 }}>
                <button className={`nbtn compact ${E.playlistLoop ? "glow pressed" : ""}`}
                  style={{ flex: 1, padding: "3px 5px", fontSize: 8 }}
                  onClick={() => E.setPlaylistLoop(!E.playlistLoop)}>↻ Loop</button>
                <button className={`nbtn compact ${E.playlistShuffle ? "glow pressed" : ""}`}
                  style={{ flex: 1, padding: "3px 5px", fontSize: 8 }}
                  onClick={() => E.setPlaylistShuffle(!E.playlistShuffle)}>⇄ Shuffle</button>
              </div>
            </div>
            {/* Audio list */}
            <div style={{ flex: 1, overflowY: "auto", padding: 6, minHeight: 0 }}>
              {E.queue.length === 0 && (
                <DropHint label="Drop audio files" sub="MP3 · WAV · OGG · M4A" />
              )}
              {E.queue.map((q, i) => (
                <PlaylistRow key={i} idx={i} name={q.name}
                  active={i === E.queueIdx} accent="var(--accent)"
                  onPlay={() => E.playFromQueue(i)}
                  onRemove={() => E.removeFromQueue(i)}
                  draggable onDragStart={onItemDragStart("audio", i)}
                  onDragOver={onItemDragOver} onDrop={onItemDrop("audio", i)} />
              ))}
            </div>
            {/* Audio footer */}
            <div style={{
              padding: 6, display: "flex", gap: 4,
              borderTop: "1px solid rgba(255,255,255,0.06)",
              background: "linear-gradient(180deg, var(--panel-lo), #0a0a0c)",
            }}>
              <input ref={aInputRef} type="file" multiple accept="audio/*" hidden onChange={onAudioFiles} />
              <button className="nbtn compact glow pressed" style={{ flex: 1, padding: "4px 6px", fontSize: 9 }}
                onClick={() => aInputRef.current.click()}>+ Audio</button>
              <button className="nbtn compact danger" style={{ padding: "4px 6px", fontSize: 9 }}
                onClick={() => E.clearQueue()} disabled={!E.queue.length}>×</button>
            </div>
          </div>

          {/* === VISUAL COLUMN === */}
          <div style={{ display: "flex", flexDirection: "column", minHeight: 0 }}>
            <div style={{ padding: 10, background: "rgba(0,0,0,0.2)",
              borderBottom: "1px solid rgba(255,255,255,0.04)" }}>
              <div className="cap" style={{ fontSize: 8, display: "flex", justifyContent: "space-between" }}>
                <span>▣ Visual Queue</span>
                <span style={{ color: "var(--led-cyan)" }}>{V.queue.length}</span>
              </div>
              <div style={{
                fontFamily: "var(--font-mono)", fontSize: 10,
                color: visualLayer ? "var(--led-cyan)" : "var(--ink-faint)",
                textShadow: visualLayer ? "0 0 4px var(--led-cyan-glow)" : "none",
                whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", marginTop: 4,
              }}>
                {visualLayer ? `${V.idx + 1}. ${visualLayer.name}` : "— empty —"}
              </div>
              <div style={{ display: "flex", gap: 4, marginTop: 6 }}>
                <button className="nbtn compact" onClick={() => V.prev()} disabled={!V.queue.length}
                  style={{ padding: "3px 5px", fontSize: 9 }}>◀◀</button>
                <button className="nbtn compact" style={{ flex: 1, padding: "3px 5px", fontSize: 9 }}
                  onClick={() => V.toggle()}
                  disabled={!V.queue.length}>
                  {V.playing ? "❚❚" : "▶"}
                </button>
                <button className="nbtn compact" onClick={() => V.next()} disabled={!V.queue.length}
                  style={{ padding: "3px 5px", fontSize: 9 }}>▶▶</button>
              </div>
              <div style={{ display: "flex", gap: 4, marginTop: 4 }}>
                <button className={`nbtn compact ${V.loop ? "glow pressed" : ""}`}
                  style={{ flex: 1, padding: "3px 5px", fontSize: 8 }}
                  onClick={() => V.setLoop(!V.loop)}>↻ Loop</button>
                <button className={`nbtn compact ${V.shuffle ? "glow pressed" : ""}`}
                  style={{ flex: 1, padding: "3px 5px", fontSize: 8 }}
                  onClick={() => V.setShuffle(!V.shuffle)}>⇄ Shuffle</button>
              </div>
              <div style={{
                display: "grid", gridTemplateColumns: "auto 1fr auto", gap: 4, alignItems: "center",
                marginTop: 6,
              }}>
                <span className="cap" style={{ fontSize: 7 }}>Per slide</span>
                <input type="range" min="0.5" max="30" step="0.1" value={V.perSlide}
                  onChange={e => V.setPerSlide(Number(e.target.value))}
                  style={{ width: "100%" }} />
                <span style={{ fontFamily: "var(--font-mono)", fontSize: 8, color: "var(--led-cyan)" }}>
                  {V.perSlide.toFixed(1)}s
                </span>
              </div>
            </div>
            <div style={{ flex: 1, overflowY: "auto", padding: 6, minHeight: 0 }}>
              {V.queue.length === 0 && (
                <DropHint label="Drop images / videos" sub="PNG · JPG · MP4 · WEBM" />
              )}
              {V.queue.map((id, i) => {
                const layer = M.layers.find(l => l.id === id);
                if (!layer) return null;
                return (
                  <PlaylistRow key={id} idx={i} name={layer.name}
                    active={i === V.idx} accent="var(--led-cyan)"
                    thumb={layer.kind === "image" ? layer.src : null}
                    kind={layer.kind}
                    onPlay={() => V.jump(i)}
                    onRemove={() => V.remove(i)}
                    draggable onDragStart={onItemDragStart("visual", i)}
                    onDragOver={onItemDragOver} onDrop={onItemDrop("visual", i)} />
                );
              })}
            </div>
            <div style={{
              padding: 6, display: "flex", gap: 4,
              borderTop: "1px solid rgba(255,255,255,0.06)",
              background: "linear-gradient(180deg, var(--panel-lo), #0a0a0c)",
            }}>
              <input ref={vInputRef} type="file" multiple accept="image/*,video/*" hidden onChange={onVisualFiles} />
              <button className="nbtn compact cyan pressed glow" style={{ flex: 1, padding: "4px 6px", fontSize: 9 }}
                onClick={() => vInputRef.current.click()}>+ Visual</button>
              <button className="nbtn compact danger" style={{ padding: "4px 6px", fontSize: 9 }}
                onClick={() => V.clear()} disabled={!V.queue.length}>×</button>
            </div>
          </div>
        </div>

        {/* Sync indicator footer */}
        <div style={{
          padding: 6, borderTop: "1px solid rgba(255,255,255,0.06)",
          fontSize: 9, fontFamily: "var(--font-mono)", color: "var(--ink-faint)",
          textAlign: "center",
          background: "linear-gradient(180deg, var(--panel-lo), #0a0a0c)",
        }}>
          Drop any file — routed to the correct queue automatically. Both queues run in parallel.
        </div>
      </div>
    );
  }

  function PlaylistRow({ idx, name, active, accent, onPlay, onRemove, thumb, kind, ...drag }) {
    return (
      <div {...drag}
        onClick={onPlay}
        style={{
          display: "grid", gridTemplateColumns: "16px 28px 1fr auto", gap: 4, alignItems: "center",
          padding: "5px 6px",
          background: active
            ? `linear-gradient(90deg, ${accent}33, transparent)`
            : "transparent",
          border: active ? `1px solid ${accent}66` : "1px solid rgba(255,255,255,0.03)",
          borderRadius: 4, marginBottom: 2, cursor: "grab",
        }}>
        <span style={{ fontFamily: "var(--font-mono)", fontSize: 8,
          color: active ? accent : "var(--ink-faint)", textAlign: "right" }}>
          {active ? "▶" : String(idx + 1).padStart(2, "0")}
        </span>
        <div style={{
          width: 26, height: 18, borderRadius: 2, background: "#000", overflow: "hidden",
          display: "grid", placeItems: "center",
          border: "1px solid rgba(255,255,255,0.06)",
        }}>
          {thumb ? <img src={thumb} style={{ width: "100%", height: "100%", objectFit: "cover" }} alt="" />
            : <span style={{ fontSize: 11, color: accent, opacity: 0.6 }}>
                {kind === "video" ? "▶" : kind === "image" ? "▣" : "♪"}
              </span>}
        </div>
        <span style={{
          fontFamily: "var(--font-mono)", fontSize: 9,
          color: active ? "var(--ink)" : "var(--ink-dim)",
          whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis",
        }}>{name}</span>
        <button onClick={(e) => { e.stopPropagation(); onRemove(); }}
          style={{
            border: "none", background: "transparent", cursor: "pointer",
            color: "var(--ink-faint)", padding: 0, fontSize: 10, lineHeight: 1,
          }}>×</button>
      </div>
    );
  }
  function DropHint({ label, sub }) {
    return (
      <div style={{
        padding: 20, textAlign: "center", color: "var(--ink-faint)", fontSize: 10, lineHeight: 1.6,
        border: "1.5px dashed rgba(255,255,255,0.08)", borderRadius: 8,
      }}>
        {label}<br/>
        <span style={{ fontSize: 9, opacity: 0.7 }}>{sub}</span>
      </div>
    );
  }

  function mount() {
    if (!window.React || !window.ReactDOM) { setTimeout(mount, 100); return; }
    let host = document.getElementById("__playlist_panel");
    if (!host) {
      host = document.createElement("div");
      host.id = "__playlist_panel";
      document.body.appendChild(host);
    }
    ReactDOM.createRoot(host).render(<PlaylistPanel />);
  }
  if (document.readyState === "complete" || document.readyState === "interactive") setTimeout(mount, 700);
  else document.addEventListener("DOMContentLoaded", () => setTimeout(mount, 700));
})();
