/* ========================================================================
   LUMINA — Floating Popup Monitor windows + Slideshow workspace
   Draggable preview/output panels you can keep on top of the UI.
   Slideshow builder with auto-transitions between PNG/JPG/MP4 layers.
   ======================================================================== */
const { useState: useStateMon, useEffect: useEffectMon, useRef: useRefMon } = React;

/* ============ Floating Popup Monitor ============ */
function PopupMonitor({ mode, onClose, sourceCanvasRef, label, color = "#ff7a1a" }) {
  const cnvRef = useRefMon(null);
  const winRef = useRefMon(null);
  const [pos, setPos] = useStateMon({ x: 80 + Math.random() * 240, y: 100 + Math.random() * 80 });
  const [size, setSize] = useStateMon({ w: 360, h: 220 });

  useEffectMon(() => {
    let raf;
    const tick = () => {
      const out = cnvRef.current;
      const src = sourceCanvasRef?.current;
      if (out && src) {
        const ctx = out.getContext("2d");
        out.width = size.w * 2;
        out.height = size.h * 2;
        out.style.width = size.w + "px";
        out.style.height = size.h + "px";
        ctx.imageSmoothingQuality = "high";
        try { ctx.drawImage(src, 0, 0, out.width, out.height); } catch (e) {}
      }
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [size, sourceCanvasRef]);

  const startDrag = (e) => {
    if (e.target.tagName === "BUTTON" || e.target.tagName === "INPUT") 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 startResize = (e) => {
    e.stopPropagation();
    const start = { x: e.clientX, y: e.clientY };
    const ss = { ...size };
    const onMove = (m) => setSize({
      w: Math.max(220, ss.w + (m.clientX - start.x)),
      h: Math.max(140, ss.h + (m.clientY - start.y)),
    });
    const onUp = () => {
      window.removeEventListener("mousemove", onMove);
      window.removeEventListener("mouseup", onUp);
    };
    window.addEventListener("mousemove", onMove);
    window.addEventListener("mouseup", onUp);
  };

  return (
    <div ref={winRef}
      style={{
        position: "fixed", left: pos.x, top: pos.y,
        width: size.w, zIndex: 500,
        background: "linear-gradient(180deg, var(--panel-hi), var(--panel-lo))",
        borderRadius: 8,
        boxShadow: `0 20px 60px rgba(0,0,0,0.8), 0 0 0 2px ${color}, 0 0 20px ${color}66`,
        overflow: "hidden",
        cursor: "move",
      }}>
      {/* Title bar */}
      <div onMouseDown={startDrag}
        style={{
          padding: "6px 10px",
          background: `linear-gradient(180deg, ${color}40, transparent)`,
          borderBottom: "1px solid rgba(255,255,255,0.06)",
          display: "flex", alignItems: "center", gap: 8,
          userSelect: "none",
        }}>
        <div style={{
          width: 8, height: 8, borderRadius: "50%",
          background: color, boxShadow: `0 0 6px ${color}`,
          animation: mode === "live" ? "pulse 1.2s infinite" : "none",
        }} />
        <span style={{
          flex: 1, fontFamily: "var(--font-display)", fontSize: 10, fontWeight: 700,
          letterSpacing: "0.16em", textTransform: "uppercase", color,
          textShadow: `0 0 4px ${color}80`,
        }}>{label}</span>
        <span style={{ fontFamily: "var(--font-mono)", fontSize: 9, color: "var(--ink-faint)" }}>
          {size.w}×{size.h}
        </span>
        <button className="nbtn compact" style={{ padding: "2px 6px", fontSize: 9 }}
          onClick={onClose}>×</button>
      </div>
      {/* Canvas */}
      <div style={{ position: "relative", background: "#000" }}>
        <canvas ref={cnvRef} style={{ display: "block", width: size.w, height: size.h }} />
        {/* corner markers */}
        <div style={{
          position: "absolute", top: 6, left: 8,
          fontFamily: "var(--font-mono)", fontSize: 8, color,
          textShadow: `0 0 3px ${color}`, opacity: 0.8,
        }}>● {mode.toUpperCase()}</div>
      </div>
      {/* Resize handle */}
      <div onMouseDown={startResize}
        style={{
          position: "absolute", right: 0, bottom: 0,
          width: 18, height: 18, cursor: "nwse-resize",
          background: "linear-gradient(135deg, transparent 50%, " + color + " 50%)",
          opacity: 0.5,
        }} />
    </div>
  );
}

/* ============ Slideshow Workspace ============ */
const SLIDESHOW_TRANSITIONS = [
  "fade", "fadeBlack", "fadeWhite", "wipeR", "wipeL",
  "pushL", "pushR", "iris", "irisOut", "slice",
  "zoomBlur", "mosaic", "dissolve", "bars", "radial",
];

function Slideshow({ audio, params }) {
  const M = window.MediaStore;
  const [, force] = useStateMon(0);
  useEffectMon(() => M?.on(() => force(n => n + 1)), []);

  const [order, setOrder] = useStateMon([]); // array of media layer ids
  useEffectMon(() => {
    // initial order = current media layers
    if (M) setOrder(M.layers.map(l => l.id));
  }, []);

  // keep order in sync with new imports
  useEffectMon(() => {
    if (!M) return;
    const ids = M.layers.map(l => l.id);
    setOrder(prev => {
      const filtered = prev.filter(id => ids.includes(id));
      const newOnes = ids.filter(id => !filtered.includes(id));
      return [...filtered, ...newOnes];
    });
  }, [M?.layers?.length]);

  const [playing, setPlaying] = useStateMon(false);
  const [perSlideDur, setPerSlideDur] = useStateMon(4);
  const [transition, setTransition] = useStateMon("fade");
  const [transDur, setTransDur] = useStateMon(0.8);
  const [randomize, setRandomize] = useStateMon(false);
  const [loop, setLoop] = useStateMon(true);
  const [autoTrans, setAutoTrans] = useStateMon(true);

  const [idx, setIdx] = useStateMon(0);
  const [progress, setProgress] = useStateMon(0); // 0..1 within current slide
  const cnvRef = useRefMon(null);
  const bufA = useRefMon(null);
  const bufB = useRefMon(null);
  const slideStartRef = useRefMon(performance.now());
  const transStartRef = useRefMon(0);
  const transitioningRef = useRefMon(false);
  const prevIdxRef = useRefMon(0);
  const dragOverIdx = useRefMon(-1);

  // playback loop
  useEffectMon(() => {
    let raf;
    const tick = () => {
      const cnv = cnvRef.current;
      if (!cnv || order.length === 0) { raf = requestAnimationFrame(tick); return; }
      const rect = cnv.parentElement.getBoundingClientRect();
      const dpr = Math.min(2, window.devicePixelRatio || 1);
      cnv.width = Math.max(2, Math.floor(rect.width * dpr));
      cnv.height = Math.max(2, Math.floor(rect.height * dpr));
      cnv.style.width = rect.width + "px";
      cnv.style.height = rect.height + "px";
      const W = cnv.width, H = cnv.height;
      const ctx = cnv.getContext("2d");

      // ensure offscreens
      if (!bufA.current) bufA.current = document.createElement("canvas");
      if (!bufB.current) bufB.current = document.createElement("canvas");
      if (bufA.current.width !== W || bufA.current.height !== H) {
        bufA.current.width = W; bufA.current.height = H;
        bufB.current.width = W; bufB.current.height = H;
      }

      const now = performance.now();
      if (playing) {
        const slideMs = perSlideDur * 1000;
        const transMs = transDur * 1000;
        const elapsed = now - slideStartRef.current;
        setProgress(Math.min(1, elapsed / slideMs));
        // start transition near end of slide
        if (autoTrans && !transitioningRef.current && elapsed > slideMs - transMs && order.length > 1) {
          transitioningRef.current = true;
          transStartRef.current = now;
          prevIdxRef.current = idx;
          const next = randomize
            ? Math.floor(Math.random() * order.length)
            : (idx + 1) % order.length;
          if (!loop && next < idx) { setPlaying(false); transitioningRef.current = false; }
          else setIdx(next);
        }
        if (elapsed > slideMs) {
          slideStartRef.current = now;
          if (!autoTrans) {
            prevIdxRef.current = idx;
            setIdx(i => (i + 1) % order.length);
          }
        }
      }

      // draw current slide to bufB
      drawMediaToBuffer(bufB.current.getContext("2d"), W, H, M.layers.find(l => l.id === order[idx]));
      // if transitioning, draw prev to bufA
      if (transitioningRef.current) {
        drawMediaToBuffer(bufA.current.getContext("2d"), W, H, M.layers.find(l => l.id === order[prevIdxRef.current]));
        const tElapsed = (now - transStartRef.current) / 1000;
        const tp = Math.min(1, tElapsed / transDur);
        const eased = tp < 0.5 ? 2 * tp * tp : 1 - Math.pow(-2 * tp + 2, 2) / 2;
        const T = window.Transitions;
        if (T) {
          const saved = T.current;
          T.current = transition;
          T.bufA = bufA.current; T.bufB = bufB.current;
          T.compose(ctx, W, H, eased);
          T.current = saved;
        } else {
          ctx.drawImage(bufB.current, 0, 0, W, H);
        }
        if (tp >= 1) transitioningRef.current = false;
      } else {
        ctx.drawImage(bufB.current, 0, 0, W, H);
      }

      // overlay info
      ctx.fillStyle = "rgba(0,0,0,0.45)";
      ctx.fillRect(8, H - 38, 240, 30);
      ctx.fillStyle = "var(--accent)";
      ctx.font = "600 14px monospace";
      ctx.fillText(`${idx + 1}/${order.length}`, 16, H - 18);
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [order, playing, idx, perSlideDur, transition, transDur, autoTrans, randomize, loop]);

  const onPlay = () => {
    setPlaying(p => !p);
    slideStartRef.current = performance.now();
  };
  const onNext = () => {
    if (order.length < 2) return;
    transitioningRef.current = true;
    transStartRef.current = performance.now();
    prevIdxRef.current = idx;
    setIdx(i => (i + 1) % order.length);
    slideStartRef.current = performance.now();
  };
  const onPrev = () => {
    if (order.length < 2) return;
    transitioningRef.current = true;
    transStartRef.current = performance.now();
    prevIdxRef.current = idx;
    setIdx(i => (i - 1 + order.length) % order.length);
    slideStartRef.current = performance.now();
  };

  /* drag & drop reorder */
  const onDragStart = (e, i) => { e.dataTransfer.setData("text/plain", String(i)); e.dataTransfer.effectAllowed = "move"; };
  const onDragOver = (e, i) => { e.preventDefault(); dragOverIdx.current = i; };
  const onDrop = (e, i) => {
    e.preventDefault();
    const from = Number(e.dataTransfer.getData("text/plain"));
    if (Number.isNaN(from) || from === i) return;
    setOrder(arr => {
      const cp = [...arr];
      const [m] = cp.splice(from, 1);
      cp.splice(i, 0, m);
      return cp;
    });
  };
  const removeFromOrder = (id) => setOrder(arr => arr.filter(x => x !== id));

  const fileRef = useRefMon(null);
  const onFiles = async (e) => {
    for (const f of e.target.files) await M?.add(f);
    e.target.value = "";
  };

  return (
    <div className="panel stage-bezel" style={{ padding: 0, display: "flex", flexDirection: "column", overflow: "hidden" }}>
      <Screws />
      <div className="stage-toolbar">
        <div className="stage-tabs"><div className="stage-tab active">Slideshow</div></div>
        <div style={{ flex: 1 }} />
        <input ref={fileRef} type="file" multiple accept="image/*,video/*" hidden onChange={onFiles} />
        <button className="nbtn compact glow pressed" onClick={() => fileRef.current.click()}>+ Import</button>
        <Lcd tone="cyan" style={{ fontSize: 10, padding: "4px 8px" }}>
          {idx + 1} / {order.length}
        </Lcd>
        <button className="nbtn compact" onClick={onPrev} disabled={order.length < 2}>◀</button>
        <button className={`nbtn compact ${playing ? "glow pressed" : ""}`}
          onClick={onPlay} disabled={order.length === 0}
          style={{ minWidth: 50, fontWeight: 700 }}>
          {playing ? "■ Stop" : "▶ Play"}
        </button>
        <button className="nbtn compact" onClick={onNext} disabled={order.length < 2}>▶</button>
      </div>

      <div className="lum-wsgrid" style={{ display: "grid", gridTemplateColumns: "220px 1fr 240px", flex: 1, minHeight: 0 }}>
        {/* Sequence list */}
        <div style={{
          padding: 10, background: "linear-gradient(180deg, #14141a, #0a0a0c)",
          borderRight: "1px solid rgba(255,255,255,0.04)",
          display: "flex", flexDirection: "column", gap: 6, overflowY: "auto",
        }}>
          <div className="cap">Sequence ({order.length})</div>
          <div style={{ fontSize: 9, color: "var(--ink-faint)", lineHeight: 1.4 }}>
            Drag to reorder · Click to jump
          </div>
          {order.length === 0 && (
            <div style={{ padding: 16, textAlign: "center", color: "var(--ink-faint)", fontSize: 10,
              border: "1.5px dashed rgba(255,255,255,0.08)", borderRadius: 8 }}>
              Empty. Click + Import to add images/videos.
            </div>
          )}
          {order.map((id, i) => {
            const layer = M?.layers.find(l => l.id === id);
            if (!layer) return null;
            return (
              <div key={id}
                draggable
                onDragStart={(e) => onDragStart(e, i)}
                onDragOver={(e) => onDragOver(e, i)}
                onDrop={(e) => onDrop(e, i)}
                onClick={() => {
                  transitioningRef.current = true;
                  transStartRef.current = performance.now();
                  prevIdxRef.current = idx;
                  setIdx(i);
                  slideStartRef.current = performance.now();
                }}
                style={{
                  display: "grid", gridTemplateColumns: "20px 40px 1fr auto",
                  gap: 6, alignItems: "center", padding: 5,
                  background: i === idx
                    ? "linear-gradient(90deg, rgba(255,122,26,0.2), rgba(255,122,26,0.06))"
                    : "linear-gradient(180deg, var(--panel-hi), var(--panel))",
                  border: i === idx ? "1px solid rgba(255,122,26,0.4)" : "1px solid rgba(255,255,255,0.04)",
                  borderRadius: 6, cursor: "grab", userSelect: "none",
                }}>
                <span style={{ fontFamily: "var(--font-mono)", fontSize: 9, color: "var(--ink-faint)" }}>
                  {String(i + 1).padStart(2, "0")}
                </span>
                <div style={{
                  width: 40, height: 24, borderRadius: 3, background: "#000", overflow: "hidden",
                  display: "grid", placeItems: "center",
                  border: "1px solid rgba(255,255,255,0.08)",
                }}>
                  {layer.kind === "image" && <img src={layer.src} style={{ width: "100%", height: "100%", objectFit: "cover" }} />}
                  {layer.kind === "video" && <span style={{ fontSize: 11, color: "var(--led-cyan)" }}>▶</span>}
                </div>
                <span style={{
                  fontSize: 10, color: i === idx ? "var(--accent)" : "var(--ink)",
                  fontFamily: "var(--font-mono)", whiteSpace: "nowrap",
                  overflow: "hidden", textOverflow: "ellipsis",
                }}>{layer.name}</span>
                <button className="nbtn compact" style={{ padding: 3, fontSize: 8 }}
                  onClick={(e) => { e.stopPropagation(); removeFromOrder(id); }}>×</button>
              </div>
            );
          })}
        </div>

        {/* Preview canvas */}
        <div style={{ position: "relative", background: "#000" }}>
          <canvas ref={cnvRef} style={{ display: "block", width: "100%", height: "100%" }} />
          {/* progress bar */}
          <div style={{
            position: "absolute", bottom: 0, left: 0, right: 0, height: 3,
            background: "rgba(0,0,0,0.5)",
          }}>
            <div style={{
              height: "100%", width: `${progress * 100}%`,
              background: "linear-gradient(90deg, var(--accent-glow), var(--accent))",
              boxShadow: "0 0 6px var(--accent-glow)",
            }} />
          </div>
          <div className="screen-corner" style={{ top: 10, left: 14 }}>
            ● SLIDESHOW · {transition.toUpperCase()} ({transDur.toFixed(1)}s)
          </div>
        </div>

        {/* Settings */}
        <div style={{
          padding: 10, background: "linear-gradient(180deg, #14141a, #0a0a0c)",
          borderLeft: "1px solid rgba(255,255,255,0.04)",
          display: "flex", flexDirection: "column", gap: 8, overflowY: "auto",
        }}>
          <div className="cap">Playback</div>
          <SI label="Slide" value={perSlideDur} onChange={setPerSlideDur} min={0.5} max={30} step={0.1} unit="s" />
          <SI label="Trans" value={transDur} onChange={setTransDur} min={0.1} max={3} step={0.05} unit="s" />
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
            <span className="cap">Auto-transition</span>
            <Flip value={autoTrans} onChange={setAutoTrans} />
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
            <span className="cap">Loop</span>
            <Flip value={loop} onChange={setLoop} />
          </div>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
            <span className="cap">Shuffle</span>
            <Flip value={randomize} onChange={setRandomize} />
          </div>

          <div className="cap" style={{ marginTop: 6 }}>Transition Style</div>
          <select value={transition} onChange={e => setTransition(e.target.value)}
            style={{
              padding: "5px 7px",
              background: "linear-gradient(180deg,#0a0a0c,#14141a)",
              border: "none", borderRadius: 4, outline: "none",
              color: "var(--accent)", textShadow: "0 0 3px var(--accent-glow)",
              fontFamily: "var(--font-mono)", fontSize: 10,
              boxShadow: "var(--nshadow-in-sm)",
            }}>
            {SLIDESHOW_TRANSITIONS.map(t => (
              <option key={t} value={t}>{window.Transitions?.presets[t]?.label || t}</option>
            ))}
          </select>

          <div className="cap" style={{ marginTop: 8 }}>Random per Slide</div>
          <button className="nbtn compact"
            onClick={() => {
              const r = SLIDESHOW_TRANSITIONS[Math.floor(Math.random() * SLIDESHOW_TRANSITIONS.length)];
              setTransition(r);
            }}>
            🎲 Random Transition
          </button>

          <div style={{
            marginTop: 10, padding: 8,
            background: "rgba(255,174,58,0.06)",
            border: "1px solid rgba(255,174,58,0.15)",
            borderRadius: 6, fontSize: 9, lineHeight: 1.5, color: "var(--ink-dim)",
          }}>
            <b style={{ color: "var(--accent)" }}>Tip:</b> Drag items to reorder. Transition starts {transDur.toFixed(1)}s
            before each slide ends, so changes are never abrupt.
          </div>
        </div>
      </div>
    </div>
  );
}

/* Helper: draw a media layer (image or video) into a buffer canvas */
function drawMediaToBuffer(ctx, W, H, layer) {
  ctx.fillStyle = "#000";
  ctx.fillRect(0, 0, W, H);
  if (!layer || !layer.el) return;
  const sr = layer.w / layer.h, tr = W / H;
  let dw, dh;
  if (sr > tr) { dh = H; dw = H * sr; } else { dw = W; dh = W / sr; }
  ctx.drawImage(layer.el, (W - dw) / 2, (H - dh) / 2, dw, dh);
}

/* Inline slider */
function SI({ label, value, onChange, min, max, step, unit = "" }) {
  return (
    <div style={{ display: "grid", gridTemplateColumns: "40px 1fr 44px", gap: 6, alignItems: "center" }}>
      <span className="cap" style={{ fontSize: 8 }}>{label}</span>
      <HSlider value={value} onChange={onChange} min={min} max={max} />
      <span style={{ fontFamily: "var(--font-mono)", fontSize: 9, color: "var(--accent)",
        textShadow: "0 0 3px var(--accent-glow)", textAlign: "right" }}>
        {step >= 1 ? value.toFixed(0) : value.toFixed(2)}{unit}
      </span>
    </div>
  );
}

window.PopupMonitor = PopupMonitor;
window.Slideshow = Slideshow;
