/* ========================================================================
   LUMINA — Popout Manager (modular multi-window UI)
   Any workspace can live in its own OS window — drag it to any screen and
   keep working in the main window. All windows share the same engines
   (AudioEngine, Prog, LuminaStack, LuminaMapping, LuminaNodes, Clock, MIDI,
   Serial): the popout renders React into the child window's document while
   the code runs in the main context, so everything stays in sync.
   ======================================================================== */
(function () {
  const { useState: useStateP, useEffect: useEffectP } = React;

  const POPOUT_DEFS = {
    composition: { title: "Live Loops",  get: () => window.CompositionDeck,
      props: (S) => ({ vizId: S.vizId, setVizId: window.__setVizId, params: S.params, onParam: S.onParam, audio: S.audio }) },
    slideshow:   { title: "Slideshow",   get: () => window.Slideshow,
      props: (S) => ({ audio: S.audio, params: S.params }) },
    scene3d:     { title: "3D Scene",    get: () => window.Scene3D,
      props: (S) => ({ params: S.params, audio: S.audio }) },
    text:        { title: "Boards",      get: () => window.TextEditor,
      props: (S) => ({ audio: S.audio, params: S.params }) },
    mapping:     { title: "Output Map",  get: () => window.MappingWorkspace,
      props: (S) => ({ audio: S.audio, params: S.params, vizId: S.vizId }) },
    lighting:    { title: "Lighting",    get: () => window.LightingWorkspace,
      props: (S) => ({ audio: S.audio }) },
    nodes:       { title: "Nodes",       get: () => window.NodesWorkspace,
      props: () => ({ popout: true }) },
    generative:  { title: "Generative",  get: () => window.GenerativePanel,
      props: () => ({}) },
  };

  /* Bridges live audio/params/viz into popped-out workspace components. */
  function PopoutHost({ kind }) {
    const def = POPOUT_DEFS[kind];
    const [audio, setAudio] = useStateP({ bass: 0, mid: 0, high: 0, energy: 0, beat: 0 });
    useEffectP(() => {
      let raf, last = 0;
      const tick = () => {
        const A = window.AudioEngine || {};
        const now = performance.now();
        if (now - last > 33) {
          last = now;
          setAudio({ bass: A.bass || 0, mid: A.mid || 0, high: A.high || 0, energy: A.energy || 0, beat: A.beat || 0 });
        }
        raf = requestAnimationFrame(tick);
      };
      raf = requestAnimationFrame(tick);
      return () => cancelAnimationFrame(raf);
    }, []);
    const S = {
      audio,
      params: window.__paramsSnapshot ? window.__paramsSnapshot() : {},
      vizId: window.__vizIdSnapshot ? window.__vizIdSnapshot() : null,
      onParam: (k, v) => {
        const p = window.__paramsSnapshot ? window.__paramsSnapshot() : {};
        if (window.__paramsApply) window.__paramsApply({ ...p, [k]: v });
      },
    };
    const Comp = def && def.get();
    if (!Comp) {
      return (
        <div style={{ color: "#888", padding: 24, fontFamily: "monospace", fontSize: 12 }}>
          Module "{kind}" is not loaded.
        </div>
      );
    }
    return <Comp {...def.props(S)} />;
  }

  const Popout = {
    wins: {},     // kind -> { win, root }
    listeners: new Set(),
    on(fn) { this.listeners.add(fn); return () => this.listeners.delete(fn); },
    _emit() { this.listeners.forEach(fn => { try { fn(this); } catch (e) {} }); },

    isOpen(kind) {
      const e = this.wins[kind];
      return !!(e && e.win && !e.win.closed);
    },

    open(kind) {
      if (!POPOUT_DEFS[kind]) return;
      if (this.isOpen(kind)) { this.wins[kind].win.focus(); return; }
      const win = window.open("", "lumina_pop_" + kind,
        "width=1500,height=900,menubar=no,toolbar=no,location=no,status=no");
      if (!win) { alert("Popup blocked — allow popups for Lumina."); return; }
      const base = window.location.href.replace(/[^/]*$/, "");
      win.document.write(
        '<!doctype html><html><head><meta charset="utf-8">' +
        '<title>Lumina · ' + (POPOUT_DEFS[kind].title) + '</title>' +
        '<link rel="preconnect" href="https://fonts.googleapis.com">' +
        '<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>' +
        '<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700;800&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">' +
        '<link rel="stylesheet" href="' + base + 'styles.css">' +
        '<link rel="stylesheet" href="' + base + 'styles-components.css">' +
        '<style>html,body{height:100%;margin:0;background:#0a0a0c;overflow:hidden}' +
        '#pop-root{height:100vh;display:flex;flex-direction:column;padding:8px;box-sizing:border-box}' +
        '#pop-root>*{flex:1;min-height:0}</style>' +
        '</head><body><div id="pop-root"></div></body></html>');
      win.document.close();
      const host = win.document.getElementById("pop-root");
      const root = ReactDOM.createRoot(host);
      root.render(<PopoutHost kind={kind} />);
      this.wins[kind] = { win, root };
      win.addEventListener("beforeunload", () => {
        try { root.unmount(); } catch (e) {}
        delete this.wins[kind];
        setTimeout(() => this._emit(), 50);
      });
      this._emit();
    },

    close(kind) {
      const e = this.wins[kind];
      if (e && e.win && !e.win.closed) e.win.close();
      delete this.wins[kind];
      this._emit();
    },

    closeAll() { Object.keys(this.wins).forEach(k => this.close(k)); },
  };

  window.LuminaPopout = Popout;
  window.addEventListener("beforeunload", () => { try { Popout.closeAll(); } catch (e) {} });
})();
