/* Screenplay editor. Live mode: editable scenes + dialogue lines via API.
   Fixture mode: read-only screenplay text from SAMPLE. */

const ScreenScript = function ScreenScript(props) {
  const data = props.data;
  const onJumpToPrompt = props.onJumpToPrompt;
  const onJumpToShot   = props.onJumpToShot;
  const isLive = Boolean(data._live) && Boolean(data._api_screenplay);
  const project = data.project;
  const [selected, setSelected] = React.useState(data.shots && data.shots[0] ? data.shots[0].id : null);
  const [activeSceneId, setActiveSceneId] = React.useState(null);

  if (isLive) return React.createElement(LiveScriptEditor, { data: data, onJumpToPrompt: onJumpToPrompt, onJumpToShot: onJumpToShot });

  const jumpToScene = (sceneId) => {
    setActiveSceneId(sceneId);
    const el = document.getElementById('script-scene-' + sceneId);
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
  };

  return (
    <div className="page" style={{ display: "grid", gridTemplateRows: "auto 1fr", height: "100%" }}>
      <PageHeader title="Screenplay" sub={"Stage 04 / 09 - " + project.title}>
        <button className="btn primary" onClick={() => onJumpToPrompt && onJumpToPrompt(selected)}>Open prompt panel</button>
      </PageHeader>

      <div style={{ display: "grid", gridTemplateColumns: "200px 1fr", height: "100%", overflow: "hidden" }}>
        <div className="panel">
          <div className="panel-header"><div className="htitle">Scenes</div></div>
          <div className="col" style={{ padding: 8 }}>
            {data.outline.map((s) => (
              <button key={s.id} className="col"
                onClick={() => jumpToScene(s.id)}
                style={{
                  alignItems: "flex-start", padding: "8px 10px", borderRadius: 4,
                  background: activeSceneId === s.id ? "var(--bg-2)" : "transparent",
                  borderLeft: activeSceneId === s.id ? "2px solid var(--accent)" : "2px solid transparent",
                  cursor: "pointer", marginBottom: 2, gap: 2, textAlign: "left",
                }}>
                <span className="mono dim" style={{ fontSize: 10 }}>SCENE {String(s.n).padStart(2, "0")}</span>
                <span style={{ fontSize: 12.5 }}>{s.title}</span>
              </button>
            ))}
          </div>
        </div>

        <div className="scroll" style={{ background: "var(--bg)", padding: "28px 36px" }}>
          <div className="screenplay" style={{ maxWidth: 720, margin: "0 auto" }}>
            <div className="mono dim" style={{ fontSize: 11, marginBottom: 18 }}>FIXTURE PREVIEW - run a project to edit live screenplay</div>
            {data.outline.map((s) => {
              const sceneShots = (data.shots || []).filter((sh) => sh.scene === s.id);
              return (
                <div key={s.id} id={'script-scene-' + s.id} style={{ marginBottom: 36, scrollMarginTop: 16 }}>
                  <div className="mono dim" style={{ fontSize: 10, marginBottom: 4 }}>SCENE {String(s.n).padStart(2, "0")}</div>
                  <div className="slug">{(s.title || '').toUpperCase()}</div>
                  <div className="action">{s.beat}</div>
                  {s.finalframe && <div className="action" style={{ fontStyle: 'italic', opacity: 0.8 }}>Final frame: {s.finalframe}</div>}
                  {sceneShots.length > 0 && (
                    <ShotsForScene shots={sceneShots} onJumpToShot={onJumpToShot}/>
                  )}
                </div>
              );
            })}
            <div style={{ marginTop: 24, padding: 16, border: "1px dashed var(--line)", borderRadius: 4, color: "var(--fg-muted)" }}>
              <strong>Live editing</strong> appears here once you run a project.
              Click <em>+ New Project</em> in the titlebar to create one. Edits to slugline, body, speaker, and dialogue
              save automatically.
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

// Inline list of shots covering a scene. Each chip jumps to that shot in the
// Shots stage with the row pre-selected so the user can see the action.
const ShotsForScene = function ShotsForScene(props) {
  const shots = props.shots || [];
  const onJumpToShot = props.onJumpToShot;
  return (
    <div style={{ marginTop: 14, padding: '10px 12px', background: 'var(--bg-inset)', borderRadius: 4, border: '1px solid var(--line)' }}>
      <div className="mono dim" style={{ fontSize: 10, marginBottom: 6 }}>SHOTS COVERING THIS SCENE · {shots.length}</div>
      <div className="row" style={{ flexWrap: 'wrap', gap: 6 }}>
        {shots.map(function (sh) {
          return (
            <button key={sh.id}
              onClick={function () { return onJumpToShot && onJumpToShot(sh.id); }}
              title={sh._action || sh.desc || ''}
              className="row gap-sm"
              style={{
                padding: '4px 8px', fontSize: 11, background: 'var(--bg)', border: '1px solid var(--line)',
                borderRadius: 3, cursor: 'pointer', color: 'var(--fg)', alignItems: 'baseline',
              }}>
              <span className="mono dim" style={{ fontSize: 9 }}>{sh.id}</span>
              <span style={{ maxWidth: 220, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{sh.desc || sh._action || '(no description)'}</span>
              <span className="mono dim" style={{ fontSize: 9 }}>{sh.dur}s</span>
            </button>
          );
        })}
      </div>
    </div>
  );
};

const AudioCuesPanel = function AudioCuesPanel(props) {
  const sceneCardId = props.sceneCardId;
  const initial = props.initial || { music: [], sfx: [], ambience: [] };
  const shots = props.shots || [];

  const [music, setMusic] = React.useState(initial.music);
  const [sfx, setSFX] = React.useState(initial.sfx);
  const [amb, setAmb] = React.useState(initial.ambience);

  React.useEffect(function () {
    setMusic(initial.music);
    setSFX(initial.sfx);
    setAmb(initial.ambience);
  }, [JSON.stringify(initial)]);

  const api = window.CinematonAPI;

  // ---------- music ----------
  const addMusic = function () {
    const cue = { type: "score", start_condition: "scene start", end_condition: "scene end", mood: "tense", instrumentation: [], motifs: [], avoid: [], mix: { dialogue_priority: "high", music_loudness: "low", sfx_priority: "medium" } };
    if (api) {
      api.addMusicCue(sceneCardId, cue).then(function (saved) {
        setMusic(function (cur) { return cur.concat([saved]); });
      }).catch(function (err) { console.error("addMusicCue failed", err); });
    }
  };
  const patchMusic = function (cue_id, patch) {
    setMusic(function (cur) { return cur.map(function (c) { return c.cue_id === cue_id ? Object.assign({}, c, patch) : c; }); });
    if (api) api.patchMusicCue(cue_id, patch).catch(function (err) { console.error("patchMusicCue failed", err); });
  };
  const removeMusic = function (cue_id) {
    setMusic(function (cur) { return cur.filter(function (c) { return c.cue_id !== cue_id; }); });
    if (api) api.deleteMusicCue(cue_id).catch(function (err) { console.error("deleteMusicCue failed", err); });
  };

  // ---------- sfx ----------
  const addSFX = function () {
    const shotId = (shots[0] && shots[0].id) || "";
    if (!shotId) { alert("Add a shot to this scene before creating an SFX cue."); return; }
    const cue = { shot_id: shotId, description: "describe the sound", timing: "shot start", diegetic: true, intensity: "medium" };
    if (api) {
      api.addSFXCue(sceneCardId, cue).then(function (saved) {
        setSFX(function (cur) { return cur.concat([saved]); });
      }).catch(function (err) { console.error("addSFXCue failed", err); });
    }
  };
  const patchSFX = function (sfx_id, patch) {
    setSFX(function (cur) { return cur.map(function (c) { return c.sfx_id === sfx_id ? Object.assign({}, c, patch) : c; }); });
    if (api) api.patchSFXCue(sfx_id, patch).catch(function (err) { console.error("patchSFXCue failed", err); });
  };
  const removeSFX = function (sfx_id) {
    setSFX(function (cur) { return cur.filter(function (c) { return c.sfx_id !== sfx_id; }); });
    if (api) api.deleteSFXCue(sfx_id).catch(function (err) { console.error("deleteSFXCue failed", err); });
  };

  // ---------- ambience ----------
  const addAmb = function () {
    const cue = { description: "describe the ambience", mood: "uneasy" };
    if (api) {
      api.addAmbienceCue(sceneCardId, cue).then(function (saved) {
        setAmb(function (cur) { return cur.concat([saved]); });
      }).catch(function (err) { console.error("addAmbienceCue failed", err); });
    }
  };
  const patchAmb = function (cue_id, patch) {
    setAmb(function (cur) { return cur.map(function (c) { return c.cue_id === cue_id ? Object.assign({}, c, patch) : c; }); });
    if (api) api.patchAmbienceCue(cue_id, patch).catch(function (err) { console.error("patchAmbienceCue failed", err); });
  };
  const removeAmb = function (cue_id) {
    setAmb(function (cur) { return cur.filter(function (c) { return c.cue_id !== cue_id; }); });
    if (api) api.deleteAmbienceCue(cue_id).catch(function (err) { console.error("deleteAmbienceCue failed", err); });
  };

  const totalCount = music.length + sfx.length + amb.length;

  return (
    <div style={{ marginTop: 18 }}>
      <hr className="hr" style={{ margin: "14px 0" }}/>
      <div className="row" style={{ justifyContent: "space-between", alignItems: "baseline", marginBottom: 8 }}>
        <div className="card-title">Audio cues - {totalCount}</div>
        <span className="mono dim" style={{ fontSize: 10 }}>music + sfx + ambience</span>
      </div>

      <div style={{ marginBottom: 12 }}>
        <div className="row" style={{ justifyContent: "space-between", alignItems: "baseline" }}>
          <span className="mono dim" style={{ fontSize: 11 }}>MUSIC ({music.length})</span>
          <button className="btn ghost sm" onClick={addMusic}>+ Music cue</button>
        </div>
        <div className="col gap-sm" style={{ marginTop: 6 }}>
          {music.map(function (c) {
            return (
              <div key={c.cue_id} style={{ display: "grid", gridTemplateColumns: "100px 1fr 1fr 1fr 28px", gap: 8, alignItems: "center" }}>
                <select value={c.type} onChange={function (e) { return patchMusic(c.cue_id, { type: e.target.value }); }} style={{ fontSize: 11, padding: "2px 4px" }}>
                  <option value="score">score</option>
                  <option value="source_music">source</option>
                  <option value="transition">transition</option>
                  <option value="sting">sting</option>
                </select>
                <EditableField value={c.mood || ""} placeholder="mood" onSave={function (v) { return patchMusic(c.cue_id, { mood: v }); }} />
                <EditableField value={c.start_condition || ""} placeholder="start" onSave={function (v) { return patchMusic(c.cue_id, { start_condition: v }); }} />
                <EditableField value={c.end_condition || ""} placeholder="end" onSave={function (v) { return patchMusic(c.cue_id, { end_condition: v }); }} />
                <button className="btn ghost sm" onClick={function () { return removeMusic(c.cue_id); }}>x</button>
              </div>
            );
          })}
          {music.length === 0 && <span className="dim mono" style={{ fontSize: 11 }}>(no music cues)</span>}
        </div>
      </div>

      <div style={{ marginBottom: 12 }}>
        <div className="row" style={{ justifyContent: "space-between", alignItems: "baseline" }}>
          <span className="mono dim" style={{ fontSize: 11 }}>SFX ({sfx.length})</span>
          <button className="btn ghost sm" onClick={addSFX}>+ SFX cue</button>
        </div>
        <div className="col gap-sm" style={{ marginTop: 6 }}>
          {sfx.map(function (c) {
            return (
              <div key={c.sfx_id} style={{ display: "grid", gridTemplateColumns: "120px 1fr 1fr 90px 28px", gap: 8, alignItems: "center" }}>
                <select value={c.shot_id} onChange={function (e) { return patchSFX(c.sfx_id, { shot_id: e.target.value }); }} style={{ fontSize: 11, padding: "2px 4px" }}>
                  {shots.map(function (s) { return <option key={s.id} value={s.id}>{s.id}</option>; })}
                </select>
                <EditableField value={c.description || ""} placeholder="description" onSave={function (v) { return patchSFX(c.sfx_id, { description: v }); }} />
                <EditableField value={c.timing || ""} placeholder="timing" onSave={function (v) { return patchSFX(c.sfx_id, { timing: v }); }} />
                <select value={c.intensity || "medium"} onChange={function (e) { return patchSFX(c.sfx_id, { intensity: e.target.value }); }} style={{ fontSize: 11, padding: "2px 4px" }}>
                  <option value="low">low</option>
                  <option value="medium">medium</option>
                  <option value="high">high</option>
                </select>
                <button className="btn ghost sm" onClick={function () { return removeSFX(c.sfx_id); }}>x</button>
              </div>
            );
          })}
          {sfx.length === 0 && <span className="dim mono" style={{ fontSize: 11 }}>(no sfx cues)</span>}
        </div>
      </div>

      <div>
        <div className="row" style={{ justifyContent: "space-between", alignItems: "baseline" }}>
          <span className="mono dim" style={{ fontSize: 11 }}>AMBIENCE ({amb.length})</span>
          <button className="btn ghost sm" onClick={addAmb}>+ Ambience cue</button>
        </div>
        <div className="col gap-sm" style={{ marginTop: 6 }}>
          {amb.map(function (c) {
            return (
              <div key={c.cue_id} style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr 1fr 28px", gap: 8, alignItems: "center" }}>
                <EditableField value={c.description || ""} placeholder="description" onSave={function (v) { return patchAmb(c.cue_id, { description: v }); }} />
                <EditableField value={c.mood || ""} placeholder="mood" onSave={function (v) { return patchAmb(c.cue_id, { mood: v }); }} />
                <EditableField value={c.start_condition || ""} placeholder="start" onSave={function (v) { return patchAmb(c.cue_id, { start_condition: v }); }} />
                <EditableField value={c.end_condition || ""} placeholder="end" onSave={function (v) { return patchAmb(c.cue_id, { end_condition: v }); }} />
                <button className="btn ghost sm" onClick={function () { return removeAmb(c.cue_id); }}>x</button>
              </div>
            );
          })}
          {amb.length === 0 && <span className="dim mono" style={{ fontSize: 11 }}>(no ambience cues)</span>}
        </div>
      </div>
    </div>
  );
};

const LiveScriptEditor = function LiveScriptEditor(props) {
  const data = props.data;
  const onJumpToPrompt = props.onJumpToPrompt;
  const onJumpToShot   = props.onJumpToShot;
  const project = data.project;
  const apiScreenplay = data._api_screenplay || { scenes: [], lines: [] };
  const allCues = data._cues || { music: [], sfx: [], ambience: [] };
  const allShots = data.shots || [];

  const [scenes, setScenes] = React.useState(apiScreenplay.scenes || []);
  const [lines, setLines] = React.useState(apiScreenplay.lines || []);

  React.useEffect(function () {
    setScenes(apiScreenplay.scenes || []);
    setLines(apiScreenplay.lines || []);
  }, [apiScreenplay]);

  const updateScene = function (sceneId, patch) {
    setScenes(function (cur) {
      return cur.map(function (s) { return s.id === sceneId ? Object.assign({}, s, patch) : s; });
    });
    if (window.CinematonAPI) {
      window.CinematonAPI.patchScreenplayScene(sceneId, patch).catch(function (err) {
        console.error("screenplay patch failed", err);
      });
    }
  };

  const updateLine = function (lineId, patch) {
    setLines(function (cur) {
      return cur.map(function (l) { return l.id === lineId ? Object.assign({}, l, patch) : l; });
    });
    if (window.CinematonAPI) {
      window.CinematonAPI.patchDialogueLine(lineId, patch).catch(function (err) {
        console.error("dialogue patch failed", err);
      });
    }
  };

  const linesForScene = function (sceneCardId) {
    return lines.filter(function (l) { return l.scene_id === sceneCardId; });
  };

  const [activeSceneId, setActiveSceneId] = React.useState(null);
  const jumpToScene = function (id) {
    setActiveSceneId(id);
    const el = document.getElementById('script-scene-' + id);
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
  };

  return (
    <div className="page" style={{ display: "grid", gridTemplateRows: "auto 1fr", height: "100%" }}>
      <PageHeader title="Screenplay" sub={"Stage 04 / 09 - " + project.title + " - " + scenes.length + " scenes - " + lines.length + " dialogue lines"}>
        <span className="tag accent">live</span>
        <button className="btn primary" onClick={function () {
          const first = scenes[0];
          if (onJumpToPrompt && first) onJumpToPrompt(first.id);
        }}>Open prompt panel</button>
      </PageHeader>

      <div style={{ display: "grid", gridTemplateColumns: "200px 1fr", height: "100%", overflow: "hidden" }}>
        <div className="panel">
          <div className="panel-header"><div className="htitle">Scenes</div></div>
          <div className="col" style={{ padding: 8 }}>
            {scenes.map(function (sc, i) {
              const isActive = activeSceneId === sc.id;
              return (
                <button key={sc.id} className="col"
                  onClick={function () { return jumpToScene(sc.id); }}
                  style={{
                    alignItems: "flex-start", padding: "8px 10px", borderRadius: 4,
                    background: isActive ? "var(--bg-2)" : "transparent",
                    borderLeft: isActive ? "2px solid var(--accent)" : "2px solid transparent",
                    cursor: "pointer", marginBottom: 2, gap: 2, textAlign: "left",
                  }}>
                  <span className="mono dim" style={{ fontSize: 10 }}>SCENE {String(i + 1).padStart(2, "0")}</span>
                  <span style={{ fontSize: 12.5 }}>{sc.slugline || sc.id}</span>
                </button>
              );
            })}
          </div>
        </div>

        <div className="scroll" style={{ padding: "24px 32px" }}>
        <div style={{ maxWidth: 820, margin: "0 auto", display: "flex", flexDirection: "column", gap: 32 }}>
          {scenes.map(function (sc) {
            const sceneLines = linesForScene(sc.scene_card_id);
            const sceneCues = {
              music:    allCues.music.filter(function (c) { return c.scene_id === sc.scene_card_id; }),
              sfx:      allCues.sfx.filter(function (c) { return c.scene_id === sc.scene_card_id; }),
              ambience: allCues.ambience.filter(function (c) { return c.scene_id === sc.scene_card_id; }),
            };
            const sceneShots = allShots.filter(function (s) { return s.scene === sc.scene_card_id; });
            return (
              <div key={sc.id} id={'script-scene-' + sc.id} className="card" style={{ padding: "18px 22px", scrollMarginTop: 16 }}>
                <div className="row" style={{ justifyContent: "space-between", alignItems: "baseline", marginBottom: 12 }}>
                  <span className="mono dim" style={{ fontSize: 11 }}>{sc.id}</span>
                  <span className="mono dim" style={{ fontSize: 10 }}>scene_card: {sc.scene_card_id}</span>
                </div>

                <div style={{ marginBottom: 14 }}>
                  <label className="card-title">Slugline</label>
                  <EditableField value={sc.slugline} onSave={function (v) { return updateScene(sc.id, { slugline: v }); }} />
                </div>

                <div style={{ marginBottom: 14 }}>
                  <label className="card-title">Body (Fountain)</label>
                  <EditableField value={sc.body} multiline autosize onSave={function (v) { return updateScene(sc.id, { body: v }); }} />
                </div>

                <hr className="hr" style={{ margin: "14px 0" }}/>
                <div className="card-title">Dialogue lines - {sceneLines.length}</div>
                <div className="col gap-sm" style={{ marginTop: 6 }}>
                  {sceneLines.map(function (line) {
                    return (
                      <div key={line.id} style={{ display: "grid", gridTemplateColumns: "120px 1fr 1fr", gap: 8, alignItems: "center" }}>
                        <EditableField value={line.speaker_character_id} mono onSave={function (v) { return updateLine(line.id, { speaker_character_id: v }); }} />
                        <EditableField value={line.text} serif onSave={function (v) { return updateLine(line.id, { text: v }); }} />
                        <EditableField value={line.subtext || ""} placeholder="(subtext)" onSave={function (v) { return updateLine(line.id, { subtext: v }); }} />
                      </div>
                    );
                  })}
                  {sceneLines.length === 0 && (
                    <span className="dim mono" style={{ fontSize: 11 }}>(no dialogue)</span>
                  )}
                </div>

                {sceneShots.length > 0 && (
                  <ShotsForScene shots={sceneShots} onJumpToShot={onJumpToShot}/>
                )}

                <AudioCuesPanel sceneCardId={sc.scene_card_id} initial={sceneCues} shots={sceneShots}/>
              </div>
            );
          })}
          {scenes.length === 0 && (
            <div className="card" style={{ padding: 32, textAlign: "center", color: "var(--fg-muted)" }}>
              No screenplay scenes yet. Run a project to generate them.
            </div>
          )}
        </div>
        </div>
      </div>
    </div>
  );
};

window.ScreenScript = ScreenScript;
