/* Top-level app: routing, density tweak, persisted state, live-data overlay. */

const TWEAKS = /*EDITMODE-BEGIN*/{
  "density": "comfortable",
  "stage": "projects"
}/*EDITMODE-END*/;

const App = () => {
  const [tweaks, setTweak] = useTweaks(TWEAKS);
  const [stage, setStage] = React.useState(tweaks.stage || "projects");

  // Live mode: when a project_id is set (by LiveLauncher after a real run),
  // fetch the API run + adapt it to the SAMPLE shape so every screen lights
  // up with real data without per-screen rewrites.
  const [liveProjectId, setLiveProjectId] = React.useState(() => {
    try { return localStorage.getItem("cinematon_live_project_id") || null; } catch { return null; }
  });
  const [apiRun, setApiRun] = React.useState(null);
  const [apiJobs, setApiJobs] = React.useState(null);
  const [apiBatchId, setApiBatchId] = React.useState(null);
  const [apiBatchKind, setApiBatchKind] = React.useState(null); // 'preview' | 'full'
  const [liveLoading, setLiveLoading] = React.useState(false);
  const [liveError, setLiveError] = React.useState(null);

  React.useEffect(() => { document.documentElement.setAttribute("data-density", tweaks.density); }, [tweaks.density]);

  // Listen for the launcher's "run completed" event.
  React.useEffect(() => {
    const onLiveRun = (e) => {
      const id = e.detail?.project_id;
      if (!id) return;
      setLiveProjectId(id);
      try { localStorage.setItem("cinematon_live_project_id", id); } catch {}
    };
    const onLiveBatch = (e) => {
      if (e.detail?.batch_id) setApiBatchId(e.detail.batch_id);
      if (e.detail?.kind)     setApiBatchKind(e.detail.kind);
    };
    window.addEventListener("cinematon:live-run", onLiveRun);
    window.addEventListener("cinematon:live-batch", onLiveBatch);
    return () => {
      window.removeEventListener("cinematon:live-run", onLiveRun);
      window.removeEventListener("cinematon:live-batch", onLiveBatch);
    };
  }, []);

  // Fetch the API run whenever liveProjectId changes — or whenever some
  // mutation dispatches `cinematon:refresh-run` (e.g., after Add/Delete
  // character or scene).
  const [refreshNonce, setRefreshNonce] = React.useState(0);
  React.useEffect(() => {
    const onRefresh = () => setRefreshNonce((n) => n + 1);
    window.addEventListener('cinematon:refresh-run', onRefresh);
    return () => window.removeEventListener('cinematon:refresh-run', onRefresh);
  }, []);
  React.useEffect(() => {
    if (!liveProjectId || !window.CinematonAPI) return;
    let cancelled = false;
    setLiveLoading(true); setLiveError(null);
    window.CinematonAPI.getRun(liveProjectId)
      .then((r) => { if (!cancelled) { setApiRun(r); setLiveLoading(false); } })
      .catch((err) => { if (!cancelled) { setLiveError(err); setLiveLoading(false); } });
    return () => { cancelled = true; };
  }, [liveProjectId, refreshNonce]);

  // Poll the active batch status when one is set.
  React.useEffect(() => {
    if (!apiBatchId || !window.CinematonAPI) return;
    const stop = window.CinematonAPI.pollBatch(apiBatchId, {
      onUpdate: (jobs) => { if (jobs) setApiJobs(jobs); },
    });
    return stop;
  }, [apiBatchId]);

  // Build the merged data view: SAMPLE fallback overlaid with live API data.
  const data = React.useMemo(() => {
    let merged = window.SAMPLE;
    if (apiRun && window.adaptApiRunToSample) {
      merged = window.adaptApiRunToSample(apiRun, window.SAMPLE);
    }
    if (apiJobs && window.adaptApiJobsToSample && merged) {
      merged = { ...merged, jobs: window.adaptApiJobsToSample(apiJobs, merged.jobs) };
    }
    return merged;
  }, [apiRun, apiJobs]);

  const exitLiveMode = () => {
    setLiveProjectId(null); setApiRun(null); setApiJobs(null); setApiBatchId(null); setApiBatchKind(null);
    try { localStorage.removeItem("cinematon_live_project_id"); } catch {}
  };

  // ---------- titlebar handlers (#61, #62, #63, #64) ----------
  const [projectsList, setProjectsList] = React.useState([]);
  React.useEffect(() => {
    if (!window.CinematonAPI?.live) return;
    let cancelled = false;
    window.CinematonAPI.listProjects()
      .then((list) => { if (!cancelled) setProjectsList(list || []); })
      .catch(() => {});
    return () => { cancelled = true; };
  }, [liveProjectId, apiRun]); // refresh when project changes

  const onNewProject = () => {
    exitLiveMode();
    window.dispatchEvent(new CustomEvent('cinematon:open-launcher'));
  };

  const onSwitchProject = (id) => {
    setLiveProjectId(id);
    try { localStorage.setItem("cinematon_live_project_id", id); } catch {}
  };

  const onRenameProject = async (newTitle) => {
    if (!liveProjectId) return;
    try {
      // Optimistic
      setApiRun((r) => r ? { ...r, project: { ...r.project, title: newTitle } } : r);
      await window.CinematonAPI.patchProject(liveProjectId, { title: newTitle });
      // Refresh project list to update switcher
      const list = await window.CinematonAPI.listProjects();
      setProjectsList(list || []);
    } catch (err) { console.error('rename failed', err); }
  };

  const onDeleteProject = async (id) => {
    if (!confirm('Delete this project? This cannot be undone.')) return;
    try {
      await window.CinematonAPI.deleteProject(id);
      const list = await window.CinematonAPI.listProjects();
      setProjectsList(list || []);
      if (id === liveProjectId) exitLiveMode();
    } catch (err) { console.error('delete failed', err); }
  };

  const onJumpToPrompt = (shotId) => setStage("prompts");
  const onJumpToRender = () => setStage("render");

  // Cross-stage shot focus: Script scene cards link to their shots; this
  // jumps to the Shots stage with that shot pre-selected.
  const [pendingShotId, setPendingShotId] = React.useState(null);
  const onJumpToShot = (shotId) => { setPendingShotId(shotId); setStage("shots"); };

  return (
    <div className="app">
      <Titlebar
        project={data.project}
        onCommandPalette={() => {}}
        onNewProject={onNewProject}
        onSwitchProject={onSwitchProject}
        onRenameProject={onRenameProject}
        onDeleteProject={onDeleteProject}
        projects={projectsList}
        isLive={Boolean(data._live)}
      />
      <Filmstrip stages={data.stages} active={stage} onJump={(k) => setStage(k)} />

      {data._live && (
        <div className="live-banner">
          <span className="live-dot"/>
          <span>Live data · project </span>
          <code>{data._live_project_id}</code>
          {liveLoading && <span className="live-spinner"/>}
          {liveError && <span className="live-err">{liveError.message}</span>}
          <button className="live-exit" onClick={exitLiveMode} title="Switch back to sample data">exit live</button>
        </div>
      )}

      <CinematonErrorBoundary>
        {stage === "projects" && (
          <ScreenProjects
            currentProjectId={liveProjectId}
            onSelectProject={(id) => {
              onSwitchProject(id);
              setStage("concept");
            }}
            onNewProject={onNewProject}
          />
        )}
        {stage === "concept" && <ScreenConcept data={data} />}
        {stage === "bible" && <ScreenBible data={data} />}
        {stage === "outline" && <ScreenOutline data={data} />}
        {stage === "script" && <ScreenScript data={data} onJumpToPrompt={onJumpToPrompt} onJumpToShot={onJumpToShot} />}
        {stage === "shots" && <ScreenShots data={data} onJumpToPrompt={onJumpToPrompt} pendingShotId={pendingShotId} clearPendingShot={() => setPendingShotId(null)} />}
        {stage === "prompts" && <ScreenPrompts data={data} onJumpToRender={onJumpToRender} />}
        {stage === "render" && <ScreenRender data={data} projectId={liveProjectId} batchId={apiBatchId} batchKind={apiBatchKind} />}
        {stage === "review" && <ScreenReview data={data} batchId={apiBatchId} projectId={liveProjectId} />}
        {stage === "export" && <ScreenExport data={data} projectId={liveProjectId} />}
      </CinematonErrorBoundary>

      <Statusbar
        project={data.project}
        validation={data.validation}
        density={tweaks.density}
        setDensity={(v) => setTweak("density", v)}
      />

      <LiveLauncher />

      <TweaksPanel title="Tweaks">
        <TweakSection title="Display">
          <TweakRadio
            label="Density"
            value={tweaks.density}
            onChange={(v) => setTweak("density", v)}
            options={[{ value: "comfortable", label: "Comfortable" }, { value: "compact", label: "Compact" }]}
          />
        </TweakSection>
        <TweakSection title="Navigation">
          <TweakSelect
            label="Jump to stage"
            value={stage}
            onChange={(v) => setStage(v)}
            options={data.stages.map(s => ({ value: s.key, label: `${s.num} · ${s.label}` }))}
          />
        </TweakSection>
        {data._live && (
          <TweakSection title="Live data">
            <button className="ll-btn" onClick={exitLiveMode}>Switch back to sample</button>
          </TweakSection>
        )}
      </TweaksPanel>
    </div>
  );
};

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
