/* Outline — 3-minute timeline with scene cards.
   Full PRD §12.5 horror scene-card field coverage:
     horror_function, fear_question, threat_distance, threat_visibility,
     scare_type, omen, sound_trigger, tension_curve {start,peak,release}, final_frame.
   Plus base SceneCard fields: title, summary (beat), duration. */

const HORROR_FUNCTIONS = [
  "omen", "dread_build", "false_safety", "rule_violation",
  "reveal", "chase", "confrontation", "final_sting",
];
const THREAT_DISTANCES = ["far", "near", "present", "inside_the_scene", "inside_the_character"];
const THREAT_VISIBILITY = ["unseen", "heard", "shadow", "reflection", "partial", "full"];
const SCARE_TYPES = ["none", "dread", "uncanny", "misdirect", "jump", "reveal", "body", "sonic"];

const ScreenOutline = ({ data }) => {
  const { outline, project } = data;
  const total = project.runtime_target;
  const [localOutline, setLocalOutline] = React.useState(outline);
  React.useEffect(() => { setLocalOutline(outline); }, [outline]);

  const totalEst = localOutline.reduce((a, s) => a + (s.dur || 0), 0);
  const isLive = Boolean(data._live) && Boolean(window.CinematonAPI);

  // updateScene merges into local state. In live mode also PATCHes the server,
  // mapping SAMPLE-shaped fields back to the API SceneCard shape.
  // genrePatch is an object of changes to genre_fields (merged into existing).
  const updateScene = async (sc, basePatch, genrePatch) => {
    const local = { ...basePatch };
    if (genrePatch) {
      // Mirror genre patch onto SAMPLE-shaped flat fields the cards read from.
      if ("horror_function" in genrePatch) local.function = genrePatch.horror_function;
      if ("final_frame" in genrePatch)     local.finalframe = genrePatch.final_frame;
      if ("tension_curve" in genrePatch) {
        const tc = genrePatch.tension_curve;
        const start = tc.start ?? 1;
        const peak  = tc.peak  ?? 5;
        const release = tc.release ?? 3;
        local.curve = [start, start + 1, start + 2, peak - 1, peak, peak - 1, release];
      }
      // Stash other genre fields under _genre for the editor to read back
      local._genre = { ...(sc._genre || {}), ...genrePatch };
    }
    setLocalOutline((cur) => cur.map((s) => s.id === sc.id ? { ...s, ...local } : s));

    if (isLive) {
      const apiPatch = {};
      if (basePatch.title !== undefined) apiPatch.title = basePatch.title;
      if (basePatch.beat !== undefined)  apiPatch.summary = basePatch.beat;
      if (basePatch.dur !== undefined)   apiPatch.duration_seconds = Number(basePatch.dur) || 0;
      if (genrePatch) {
        const merged = { ...(sc._genre || {}) };
        // Reconstruct from local fields if _genre is empty
        if (sc.function && merged.horror_function === undefined) merged.horror_function = sc.function;
        if (sc.finalframe && merged.final_frame === undefined)   merged.final_frame = sc.finalframe;
        Object.assign(merged, genrePatch);
        apiPatch.genre_fields = merged;
      }
      try { await window.CinematonAPI.patchScene(sc.id, apiPatch); }
      catch (err) { console.error("scene patch failed", err); }
    }
  };

  const regenScene = async (sc) => {
    if (!isLive) return;
    if (!confirm(`Regenerate "${sc.title}"? This re-runs the screenplay + shots + prompts agents for this scene only. Existing edits to those artifacts will be lost.`)) return;
    try {
      await window.CinematonAPI.regenScene(sc.id);
      window.dispatchEvent(new CustomEvent('cinematon:refresh-run'));
    } catch (err) { alert('Regen failed: ' + (err.message || err)); }
  };

  const deleteScene = async (sc) => {
    if (!confirm(`Delete scene "${sc.title}"? This will also delete its shots and packets.`)) return;
    setLocalOutline((cur) => cur.filter((s) => s.id !== sc.id));
    if (isLive) {
      try { await window.CinematonAPI.deleteScene(sc.id); }
      catch (err) { console.error("scene delete failed", err); setLocalOutline(outline); }
    }
  };

  const addScene = async () => {
    const newScene = {
      outline_beat_index: localOutline.length,
      title: `Scene ${localOutline.length + 1}`,
      summary: "New beat — describe what happens.",
      duration_seconds: 30,
      characters: [],
      genre_fields: {
        horror_function: "dread_build", fear_question: "",
        threat_distance: "near", threat_visibility: "unseen",
        scare_type: "dread", tension_curve: { start: 1, peak: 5, release: 3 },
        omen: "", sound_trigger: "", final_frame: "",
      },
    };
    if (isLive && project.id) {
      try {
        const created = await window.CinematonAPI.addScene(project.id, newScene);
        setLocalOutline((cur) => [...cur, mapApiSceneToCard(created, cur.length, totalEst)]);
      } catch (err) { console.error("scene create failed", err); }
    } else {
      setLocalOutline((cur) => [...cur, {
        id: `sc_local_${Date.now()}`, n: cur.length + 1, title: newScene.title,
        in: totalEst, dur: newScene.duration_seconds,
        function: "dread_build", curve: [1,2,3,4,5,4,3],
        beat: newScene.summary, finalframe: "",
        _genre: newScene.genre_fields,
      }]);
    }
  };

  return (
    <div className="page" style={{ display: "grid", gridTemplateRows: "auto 1fr", height: "100%" }}>
      <PageHeader title="3-Minute Outline" sub={`Stage 03 / 09 · ${localOutline.length} scenes · ${fmtTime(totalEst)} of ${fmtTime(total)}`}>
        <button className="btn ghost"><Icon name="regen"/> Repropose outline</button>
        <button className="btn primary">Continue → Script</button>
      </PageHeader>

      <div style={{ overflow: "auto", padding: "20px 24px" }}>
        {/* Master timeline */}
        <div className="card" style={{ padding: 14, marginBottom: 22 }}>
          <div className="row" style={{ justifyContent: "space-between", marginBottom: 10 }}>
            <div className="card-title" style={{ margin: 0 }}>Episode timeline · horror 3-act compressed</div>
            <div className="mono dim" style={{ fontSize: 11 }}>0:00 ─────────────── 3:00</div>
          </div>
          <div style={{ position: "relative", height: 56, background: "var(--bg-inset)", borderRadius: 4, border: "1px solid var(--line)", display: "flex" }}>
            {localOutline.map((s, i) => {
              const w = (s.dur / total) * 100;
              return (
                <div key={s.id} style={{
                  flex: `0 0 ${w}%`, position: "relative",
                  borderRight: i < localOutline.length - 1 ? "1px solid var(--line)" : "none",
                  padding: "6px 8px",
                  background: i % 2 === 0 ? "transparent" : "oklch(0.18 0.005 240)",
                }}>
                  <div className="mono" style={{ fontSize: 10, color: "var(--accent)" }}>{fmtTime(s.in)}</div>
                  <div style={{ fontSize: 11, marginTop: 2, color: "var(--fg)", overflow: "hidden", whiteSpace: "nowrap", textOverflow: "ellipsis" }}>{s.function}</div>
                </div>
              );
            })}
          </div>
        </div>

        {/* Scene cards grid — every PRD §12.5 field editable */}
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(440px, 1fr))", gap: 16 }}>
          {localOutline.map((sc) => (
            <SceneCardEditor
              key={sc.id}
              sc={sc}
              isLive={isLive}
              onUpdate={(base, genre) => updateScene(sc, base, genre)}
              onDelete={() => deleteScene(sc)}
              onRegen={() => regenScene(sc)}
            />
          ))}

          {/* Add scene tile */}
          <button
            className="card"
            onClick={addScene}
            style={{
              border: "1px dashed var(--line)", background: "transparent",
              cursor: "pointer", color: "var(--fg-muted)",
              minHeight: 240, display: "flex", flexDirection: "column",
              alignItems: "center", justifyContent: "center", gap: 8,
            }}>
            <span style={{ fontSize: 24 }}>+</span>
            <span style={{ fontSize: 12 }}>Add scene</span>
          </button>
        </div>
      </div>
    </div>
  );
};

const SceneCardEditor = ({ sc, isLive, onUpdate, onDelete, onRegen }) => {
  // _genre field carries the full PRD §12.5 sub-object after first edit.
  // For initial render, derive from sc.function / sc.curve / sc.finalframe + defaults.
  const g = sc._genre || {};
  const curve = sc.curve || [1, 2, 3, 4, 5, 4, 3];
  const tcStart   = g.tension_curve?.start   ?? curve[0] ?? 1;
  const tcPeak    = g.tension_curve?.peak    ?? Math.max(...curve);
  const tcRelease = g.tension_curve?.release ?? curve[curve.length - 1] ?? 3;

  const setTC = (key, val) => {
    const v = Math.max(1, Math.min(9, Number(val) || 1));
    const next = { start: tcStart, peak: tcPeak, release: tcRelease, [key]: v };
    onUpdate({}, { tension_curve: next });
  };

  return (
    <div className="card" style={{ position: "relative" }}>
      <div className="row" style={{ justifyContent: "space-between", alignItems: "flex-start", marginBottom: 8 }}>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div className="mono dim" style={{ fontSize: 10.5 }}>SCENE {String(sc.n).padStart(2, "0")} · in {fmtTime(sc.in)}</div>
          <h3 style={{ margin: "4px 0 0" }}>
            <EditableField
              value={sc.title} serif
              onSave={(v) => onUpdate({ title: v })}
            />
          </h3>
        </div>
        <div className="row gap-sm">
          {onRegen && (
            <button
              onClick={onRegen}
              disabled={!isLive}
              title={isLive ? "Regenerate this scene's screenplay + shots + prompts" : "Regen requires a live project"}
              className="btn ghost sm">
              <Icon name="regen" size={11}/> Regen
            </button>
          )}
          <button
            onClick={onDelete}
            title="Delete scene"
            style={{ background: "transparent", border: "none", color: "var(--fg-faint)", cursor: "pointer", fontSize: 16, padding: 4 }}>⌫</button>
        </div>
      </div>

      {/* Beat (summary) */}
      <div style={{ margin: "8px 0 10px" }}>
        <label className="card-title" style={{ marginBottom: 4 }}>Beat (summary)</label>
        <EditableField
          value={sc.beat} multiline autosize
          onSave={(v) => onUpdate({ beat: v })}
        />
      </div>

      {/* Genre row 1: function + duration + scare_type */}
      <div style={{ display: "grid", gridTemplateColumns: "1.4fr 80px 1fr", gap: 8, marginBottom: 10 }}>
        <SceneInlineSelect label="Horror function" value={sc.function || g.horror_function || "dread_build"}
          options={HORROR_FUNCTIONS}
          onSave={(v) => onUpdate({}, { horror_function: v })}/>
        <SceneInlineNumber label="Dur (s)" value={sc.dur || 0}
          onSave={(v) => onUpdate({ dur: Number(v) || 0 })}/>
        <SceneInlineSelect label="Scare type" value={g.scare_type || "dread"}
          options={SCARE_TYPES}
          onSave={(v) => onUpdate({}, { scare_type: v })}/>
      </div>

      {/* Genre row 2: threat distance + visibility */}
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, marginBottom: 10 }}>
        <SceneInlineSelect label="Threat distance" value={g.threat_distance || "near"}
          options={THREAT_DISTANCES}
          onSave={(v) => onUpdate({}, { threat_distance: v })}/>
        <SceneInlineSelect label="Threat visibility" value={g.threat_visibility || "unseen"}
          options={THREAT_VISIBILITY}
          onSave={(v) => onUpdate({}, { threat_visibility: v })}/>
      </div>

      {/* Fear question */}
      <div style={{ marginBottom: 10 }}>
        <label className="card-title" style={{ marginBottom: 4 }}>Fear question</label>
        <EditableField
          value={g.fear_question || ""} placeholder="What is the audience afraid might happen?"
          onSave={(v) => onUpdate({}, { fear_question: v })}/>
      </div>

      {/* Tension curve (start / peak / release) */}
      <div className="card-title" style={{ marginBottom: 4 }}>
        Tension curve · start {tcStart} → peak {tcPeak} → release {tcRelease}
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8, marginBottom: 6 }}>
        <SceneInlineNumber label="Start (1-9)" value={tcStart} onSave={(v) => setTC("start", v)}/>
        <SceneInlineNumber label="Peak (1-9)" value={tcPeak} onSave={(v) => setTC("peak", v)}/>
        <SceneInlineNumber label="Release (1-9)" value={tcRelease} onSave={(v) => setTC("release", v)}/>
      </div>
      <div style={{ height: 36, background: "var(--bg-inset)", borderRadius: 3, padding: 4, marginBottom: 10 }}>
        <TensionCurve points={curve} height={28} width={400}/>
      </div>

      {/* Omen + sound trigger */}
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, marginBottom: 10 }}>
        <div>
          <label className="card-title" style={{ marginBottom: 4 }}>Omen</label>
          <EditableField value={g.omen || ""} placeholder="The thing that warns" onSave={(v) => onUpdate({}, { omen: v })}/>
        </div>
        <div>
          <label className="card-title" style={{ marginBottom: 4 }}>Sound trigger</label>
          <EditableField value={g.sound_trigger || ""} placeholder="What sound starts the dread" onSave={(v) => onUpdate({}, { sound_trigger: v })}/>
        </div>
      </div>

      {/* Final frame */}
      <hr className="hr" style={{ margin: "8px 0" }}/>
      <label className="card-title" style={{ marginBottom: 4 }}>Final frame</label>
      <EditableField
        value={sc.finalframe || g.final_frame || ""} serif
        placeholder="The image you remember"
        onSave={(v) => onUpdate({}, { final_frame: v })}/>
    </div>
  );
};

const SceneInlineSelect = ({ label, value, options, onSave }) => {
  const [v, setV] = React.useState(value);
  React.useEffect(() => { setV(value); }, [value]);
  return (
    <div className="col" style={{ gap: 3 }}>
      <label style={{ fontSize: 9.5, color: "var(--fg-faint)", letterSpacing: "0.06em", textTransform: "uppercase", fontFamily: "var(--font-mono)" }}>{label}</label>
      <select className="input" value={v}
        onChange={(e) => { setV(e.target.value); onSave(e.target.value); }}
        style={{ padding: "5px 8px", fontSize: 12 }}>
        {options.map((o) => <option key={o} value={o}>{o}</option>)}
      </select>
    </div>
  );
};

const SceneInlineNumber = ({ label, value, onSave }) => (
  <div className="col" style={{ gap: 3 }}>
    <label style={{ fontSize: 9.5, color: "var(--fg-faint)", letterSpacing: "0.06em", textTransform: "uppercase", fontFamily: "var(--font-mono)" }}>{label}</label>
    <EditableField value={value} mono onSave={onSave}/>
  </div>
);

// Convert API SceneCard payload to SAMPLE outline shape for local appending.
function mapApiSceneToCard(s, idx, cursor) {
  const sgf = s.genre_fields || {};
  const peak = sgf.tension_curve?.peak ?? 5;
  const start = sgf.tension_curve?.start ?? 1;
  const release = sgf.tension_curve?.release ?? 3;
  return {
    id: s.id, n: idx + 1, title: s.title,
    in: cursor, dur: s.duration_seconds,
    function: sgf.horror_function || "dread_build",
    curve: [start, start + 1, start + 2, peak - 1, peak, peak - 1, release],
    beat: s.summary, finalframe: sgf.final_frame || "",
    _genre: sgf,
  };
}

window.ScreenOutline = ScreenOutline;
