/* Tabbed Prompt Editor — the centerpiece. Form / Raw / Validation / Cost / History */

const ScreenPrompts = ({ data, onJumpToRender }) => {
  const { shots, packet: initialPacket, validation, history, cost } = data;
  const [sel, setSel] = React.useState("sh_012");
  const [tab, setTab] = React.useState("form");

  // Live edits: in live mode (data._live), patch the server on every save.
  // Always also track an optimistic local copy so the UI updates immediately.
  const [localPacket, setLocalPacket] = React.useState(initialPacket);
  const [staleShotIds, setStaleShotIds] = React.useState([]);
  React.useEffect(() => { setLocalPacket(initialPacket); }, [initialPacket]);
  const packet = localPacket;

  // savePatch(field, value) — used by FormView/RawView. In live mode, PATCHes;
  // otherwise just updates local state (so the UI still feels editable for the prototype).
  const savePatch = React.useCallback(async (path, value) => {
    const next = setDeep({ ...packet }, path, value);
    setLocalPacket(next);
    if (data._live && window.CinematonAPI && packet.shot_id) {
      const result = await window.CinematonAPI.patchPrompt(packet.shot_id, next);
      if (result?.stale_shot_ids) setStaleShotIds(result.stale_shot_ids);
    }
  }, [packet, data._live]);

  // saveRaw(rawText) — replaces the entire packet from raw JSON. Validates parse.
  const saveRaw = React.useCallback(async (rawText) => {
    let next;
    try { next = JSON.parse(rawText); }
    catch (err) { throw new Error(`Invalid JSON: ${err.message}`); }
    setLocalPacket(next);
    if (data._live && window.CinematonAPI && next.shot_id) {
      const result = await window.CinematonAPI.patchPrompt(next.shot_id, next);
      if (result?.stale_shot_ids) setStaleShotIds(result.stale_shot_ids);
    }
  }, [data._live]);

  return (
    <div className="page" style={{ display: "grid", gridTemplateRows: "auto 1fr", height: "100%" }}>
      <PageHeader title="Prompt Packet" sub={`Stage 06 / 09 · ${shots.length} packets · 19 ✓ · 1 ⚠ renderability`}>
        <button className="btn ghost"><Icon name="regen"/> Regenerate</button>
        <button className="btn ghost"><Icon name="render"/> Test render</button>
        <button className="btn primary" onClick={onJumpToRender}>Approve & Render →</button>
      </PageHeader>

      <div style={{ display: "grid", gridTemplateColumns: "260px 1fr", height: "100%", overflow: "hidden" }}>
        {/* Left: shot list */}
        <div className="panel">
          <div className="panel-header">
            <div className="htitle">Packets</div>
            <span className="mono dim" style={{ fontSize: 10 }}>{shots.length}</span>
          </div>
          <div style={{ padding: 6, overflowY: "auto" }}>
            {shots.map(s => {
              const isWarn = s.id === "sh_012" || s.id === "sh_015";
              const isStale = s.id === "sh_013" || s.id === "sh_014"; // downstream of sh_012's continuity edit
              const isSel = s.id === sel;
              return (
                <button key={s.id} onClick={() => setSel(s.id)}
                  className="row"
                  style={{
                    gap: 10, padding: "7px 10px", borderRadius: 4,
                    background: isSel ? "var(--bg-2)" : "transparent",
                    width: "100%", textAlign: "left", marginBottom: 1,
                  }}>
                  <span style={{ width: 6, height: 6, borderRadius: "50%", background: isWarn ? "var(--warn)" : isStale ? "var(--accent)" : "var(--good)", flex: "0 0 auto" }}/>
                  <span className="mono" style={{ fontSize: 11, color: isSel ? "var(--accent)" : "var(--fg-muted)", flex: "0 0 56px" }}>{s.id}</span>
                  <span style={{ fontSize: 12, color: isSel ? "var(--fg)" : "var(--fg-muted)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: 1 }}>{s.desc}</span>
                  {isStale
                    ? <span className="mono" style={{ fontSize: 9, color: "var(--accent)", letterSpacing: "0.06em" }}>STALE</span>
                    : <span className="mono dim" style={{ fontSize: 10 }}>{s.dur}s</span>}
                </button>
              );
            })}
          </div>
        </div>

        {/* Right: editor */}
        <div style={{ display: "grid", gridTemplateRows: "auto auto auto 1fr", overflow: "hidden" }}>
          {/* Header strip */}
          <div style={{ padding: "14px 22px", borderBottom: "1px solid var(--line-soft)", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
            <div>
              <div className="mono dim" style={{ fontSize: 11, marginBottom: 4 }}>{packet.shot_id} · {packet.scene_id} · {packet.provider_params.provider} · {packet.provider_params.model}</div>
              <h2 className="serif" style={{ fontStyle: "italic", fontSize: 22, margin: 0 }}>{shots.find(s=>s.id===sel)?.desc}</h2>
            </div>
            <div className="row gap-sm">
              <span className="tag warn"><Icon name="warn" size={10}/> stale · 2 edits</span>
              <span className="tag">{packet.duration_seconds}s · {packet.aspect_ratio}</span>
              <span className="tag">{packet.provider_params.resolution}</span>
            </div>
          </div>

          {/* Edit-impact strip — surfaces 14.6: downstream stale + previous version preserved */}
          <div className="edit-impact">
            <div className="edit-impact-cell warn">
              <span className="dot"/>
              <div className="col" style={{ gap: 1 }}>
                <span className="lbl">Validation</span>
                <span className="val">1 renderability warning · 0 errors</span>
              </div>
            </div>
            <div className="edit-impact-cell">
              <span className="dot accent"/>
              <div className="col" style={{ gap: 1 }}>
                <span className="lbl">Downstream stale</span>
                <span className="val">2 packets · sh_013 · sh_014 <button className="lk">Re-derive →</button></span>
              </div>
            </div>
            <div className="edit-impact-cell">
              <span className="dot ok"/>
              <div className="col" style={{ gap: 1 }}>
                <span className="lbl">Previous version</span>
                <span className="val">v6 preserved · 32s ago <button className="lk">Diff v6 ↔ v7</button> · <button className="lk">Restore</button></span>
              </div>
            </div>
            <div className="edit-impact-cell">
              <span className="dot ok"/>
              <div className="col" style={{ gap: 1 }}>
                <span className="lbl">Cost re-estimated</span>
                <span className="val mono">$2.95 · was $2.81 (+5%) · valid 4m 12s</span>
              </div>
            </div>
          </div>

          {/* Tabs */}
          <div className="tabs" style={{ paddingLeft: 14 }}>
            <button className={`tab ${tab==="form"?"active":""}`} onClick={() => setTab("form")}>Form view</button>
            <button className={`tab ${tab==="raw"?"active":""}`} onClick={() => setTab("raw")}>Raw view <span className="count">json</span></button>
            <button className={`tab ${tab==="validation"?"active":""}`} onClick={() => setTab("validation")}>Validation <span className="count">2</span></button>
            <button className={`tab ${tab==="cost"?"active":""}`} onClick={() => setTab("cost")}>Cost <span className="count mono">$2.95</span></button>
            <button className={`tab ${tab==="history"?"active":""}`} onClick={() => setTab("history")}>Render history <span className="count">{history.length}</span></button>
            <div style={{ marginLeft: "auto", padding: "0 14px", display: "flex", alignItems: "center", gap: 10 }}>
              <span className="dim mono" style={{ fontSize: 10 }}>FORM ↔ RAW SYNCED</span>
              <span className="iris" title="threat visibility"/>
            </div>
          </div>

          {/* Pane content */}
          <div className="scroll" style={{ padding: 22 }}>
            {tab === "form" && <FormView packet={packet} savePatch={savePatch}/>}
            {tab === "raw" && <RawView packet={packet} saveRaw={saveRaw}/>}
            {tab === "validation" && <ValidationView validation={validation}/>}
            {tab === "cost" && <CostTabView cost={cost} packet={packet}/>}
            {tab === "history" && <HistoryView history={history}/>}
          </div>
        </div>
      </div>
    </div>
  );
};

const FormView = ({ packet, savePatch }) => (
  <div className="col gap-md" style={{ maxWidth: 1100 }}>
    {/* Identifiers / provider — surfaces 14.4 required scalar fields up front */}
    <div className="card" style={{ background: "var(--bg-inset)" }}>
      <div className="row" style={{ justifyContent: "space-between", alignItems: "center", marginBottom: 10 }}>
        <div className="card-title" style={{ margin: 0 }}>Identifiers · Provider · Cost</div>
        <span className="mono dim" style={{ fontSize: 10 }}>14.4 · scalar fields</span>
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 10 }}>
        <FieldSlim label="Shot ID" mono value={packet.shot_id} readOnly/>
        <FieldSlim label="Scene ID" mono value={packet.scene_id} readOnly/>
        <FieldSlim label="Duration (s)" mono value={packet.duration_seconds} onSave={(v) => savePatch('duration_seconds', Number(v))}/>
        <FieldSlim label="Aspect ratio" mono value={packet.aspect_ratio} onSave={(v) => savePatch('aspect_ratio', v)}/>
        <FieldSlim label="Provider" mono value={packet.provider_params.provider} readOnly/>
        <FieldSlim label="Model" mono value={packet.provider_params.model} onSave={(v) => savePatch('provider_params.model', v)}/>
        <FieldSlim label="Resolution" mono value={packet.provider_params.resolution} onSave={(v) => savePatch('provider_params.resolution', v)}/>
        <FieldSlim label="Cost estimate" mono value="$2.95 USD" accent readOnly/>
      </div>
    </div>

    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 18 }}>
    <div className="col gap-md">
      <Field label="Subject" value={packet.subject} onSave={(v) => savePatch('subject', v)}/>
      <Field label="Setting" value={packet.setting} onSave={(v) => savePatch('setting', v)}/>
      <Field label="Action" value={packet.action} multi onSave={(v) => savePatch('action', v)}/>
      <Field label="Camera" value={packet.camera} onSave={(v) => savePatch('camera', v)}/>
      <Field label="Lens" value={packet.lens} onSave={(v) => savePatch('lens', v)}/>
      <Field label="Composition" value={packet.composition} onSave={(v) => savePatch('composition', v)}/>
    </div>
    <div className="col gap-md">
      <Field label="Lighting" value={packet.lighting} multi onSave={(v) => savePatch('lighting', v)}/>
      <Field label="Color palette" value={packet.color_palette} onSave={(v) => savePatch('color_palette', v)}/>
      <Field label="Motion" value={packet.motion} multi onSave={(v) => savePatch('motion', v)}/>
      <Field label="Visual style" value={packet.visual_style} multi onSave={(v) => savePatch('visual_style', v)}/>

      <div className="card">
        <div className="card-title">Genre modifiers · horror.v1</div>
        <dl className="dl">
          <dt>Visibility</dt><dd className="row gap-sm"><Aperture value={packet.genre_modifiers.threat_visibility} size={18}/> {packet.genre_modifiers.threat_visibility}</dd>
          <dt>Scare type</dt><dd>{packet.genre_modifiers.scare_type}</dd>
          <dt>Tension peak</dt><dd className="mono">{packet.genre_modifiers.tension_peak} / 9</dd>
          <dt>Final frame</dt><dd className="serif" style={{ fontStyle: "italic", color: "var(--accent)" }}>"{packet.genre_modifiers.final_frame}"</dd>
        </dl>
      </div>

      <div className="card">
        <div className="card-title">Continuity</div>
        <div className="col gap-sm">
          {packet.continuity_refs.map(r => <span key={r} className="mono" style={{ fontSize: 11.5, color: "var(--fg-muted)" }}>↳ {r}</span>)}
        </div>
      </div>

      <div className="card">
        <div className="card-title">Negative constraints</div>
        <div className="row gap-sm" style={{ flexWrap: "wrap" }}>
          {packet.negative_constraints.map(n => <span key={n} className="tag bad"><Icon name="x" size={10}/> {n}</span>)}
        </div>
      </div>

      <div className="card">
        <div className="card-title">Dialogue line IDs</div>
        {packet.dialogue_line_ids.length === 0
          ? <span className="dim mono" style={{ fontSize: 11 }}>— none (silent shot)</span>
          : <div className="row gap-sm" style={{ flexWrap: "wrap" }}>
              {packet.dialogue_line_ids.map(d => <span key={d} className="tag accent">{d}</span>)}
            </div>}
      </div>

      <div className="card">
        <div className="card-title">Sound cue IDs</div>
        <div className="row gap-sm" style={{ flexWrap: "wrap" }}>
          {packet.sound_cue_ids.map(s => <span key={s} className="tag accent">{s}</span>)}
        </div>
      </div>
    </div>
    </div>
  </div>
);

const FieldSlim = ({ label, value, mono, accent, onSave, readOnly }) => (
  <div className="col" style={{ gap: 3 }}>
    <label style={{ fontSize: 10, color: "var(--fg-faint)", letterSpacing: "0.06em", textTransform: "uppercase", fontFamily: "var(--font-mono)" }}>{label}</label>
    {readOnly || !onSave ? (
      <div
        className="input"
        style={{
          fontFamily: mono ? "var(--font-mono)" : "var(--font-sans)",
          fontSize: 12, padding: "6px 8px",
          color: accent ? "var(--accent)" : "var(--fg-muted)",
          fontWeight: accent ? 600 : 400,
          opacity: 0.85,
        }}>{String(value ?? "")}</div>
    ) : (
      <EditableField
        value={value} mono={mono}
        onSave={onSave}
        className={accent ? "accent" : ""}
      />
    )}
  </div>
);

const Field = ({ label, value, multi, onSave }) => (
  <div className="field">
    <label>{label}</label>
    {onSave
      ? <EditableField value={value} multiline={multi} onSave={onSave} autosize/>
      : (multi
          ? <textarea className="textarea" defaultValue={value} rows={2} />
          : <input className="input" defaultValue={value} />)
    }
  </div>
);

const RawView = ({ packet, saveRaw }) => {
  const [local, setLocal] = React.useState(JSON.stringify(packet, null, 2));
  const [dirty, setDirty] = React.useState(false);
  const [saving, setSaving] = React.useState(false);
  const [error, setError] = React.useState(null);

  React.useEffect(() => {
    if (!dirty) setLocal(JSON.stringify(packet, null, 2));
  }, [packet, dirty]);

  const commit = async () => {
    if (!dirty) return;
    setSaving(true); setError(null);
    try { await saveRaw(local); setDirty(false); }
    catch (err) { setError(err.message || 'save failed'); }
    finally { setSaving(false); }
  };

  return (
    <div style={{ background: "var(--bg-inset)", border: `1px solid ${error ? "var(--bad)" : dirty ? "var(--accent-dim)" : "var(--line)"}`, borderRadius: 6, padding: 0, overflow: "hidden" }}>
      <div className="row" style={{ padding: "8px 14px", borderBottom: "1px solid var(--line-soft)", justifyContent: "space-between" }}>
        <span className="mono dim" style={{ fontSize: 10 }}>video_prompt_packet.json · {Object.keys(packet).length} keys</span>
        <div className="row gap-sm">
          {saving && <span className="tag"><span className="ef-spin"/> saving</span>}
          {dirty && !saving && <span className="tag accent"><span className="dirty-dot"/> unsaved · blur to save</span>}
          {error && <span className="tag bad"><Icon name="x" size={10}/> {error}</span>}
          {!dirty && !saving && !error && <span className="tag good"><Icon name="check" size={10}/> JSON saved</span>}
          <span className="tag">schema: VideoPromptPacket@1.4</span>
        </div>
      </div>
      <textarea
        value={local}
        onChange={(e) => { setLocal(e.target.value); setDirty(e.target.value !== JSON.stringify(packet, null, 2)); if (error) setError(null); }}
        onBlur={commit}
        spellCheck={false}
        style={{
          width: "100%", margin: 0, padding: 16, border: "none", outline: "none",
          background: "transparent", color: "var(--fg)",
          fontFamily: "var(--font-mono)", fontSize: 12, lineHeight: 1.55,
          minHeight: 360, maxHeight: "60vh", resize: "vertical", whiteSpace: "pre",
        }}
      />
    </div>
  );
};

// setDeep("foo.bar", val) — walks the obj, creating subobjects as needed.
function setDeep(obj, path, value) {
  const parts = path.split('.');
  let cur = obj;
  for (let i = 0; i < parts.length - 1; i++) {
    const k = parts[i];
    if (cur[k] == null || typeof cur[k] !== 'object') cur[k] = {};
    else cur[k] = { ...cur[k] }; // clone level so React sees a new object
    cur = cur[k];
  }
  cur[parts[parts.length - 1]] = value;
  return obj;
}

const ValidationView = ({ validation }) => (
  <div className="col gap-md" style={{ maxWidth: 880 }}>
    <div className="card">
      <div className="card-title">Validation report · 4 layers</div>
      {validation.map((v, i) => (
        <div key={i} className={`check ${v.kind}`}>
          <span className="ico"/>
          <div className="col" style={{ gap: 2, flex: 1 }}>
            <div>{v.label}</div>
            <div className="dim" style={{ fontSize: 11 }}>{v.detail}</div>
          </div>
          <span className="mono dim" style={{ fontSize: 10 }}>{v.kind.toUpperCase()}</span>
        </div>
      ))}
    </div>

    <div className="card">
      <div className="card-title">Horror QA rubric · 9 dimensions</div>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 8 }}>
        {[
          ["Dread", 5], ["Escalation", 4], ["Specificity", 5],
          ["Visuality", 5], ["Sound", 4], ["Restraint", 5],
          ["Payoff", 4], ["Renderability", 3], ["Safety", 5],
        ].map(([k, v]) => (
          <div key={k} className="row" style={{ justifyContent: "space-between", padding: "8px 10px", background: "var(--bg-inset)", borderRadius: 4, border: "1px solid var(--line-soft)" }}>
            <span style={{ fontSize: 12 }}>{k}</span>
            <div className="row" style={{ gap: 2 }}>
              {[1,2,3,4,5].map(n => (
                <span key={n} style={{ width: 8, height: 8, borderRadius: 1, background: n <= v ? (v >= 4 ? "var(--good)" : "var(--warn)") : "var(--bg-3)" }}/>
              ))}
            </div>
          </div>
        ))}
      </div>
    </div>

    <div className="card" style={{ borderColor: "oklch(0.4 0.08 85)" }}>
      <div className="row" style={{ marginBottom: 8 }}>
        <Icon name="warn"/> <b style={{ color: "var(--warn)" }}>Renderability suggestion</b>
      </div>
      <p style={{ margin: "0 0 10px" }}>The held shadow at 0:06 may animate stochastically. Recommend pinning a reference image at 0:06 to constrain the final frame.</p>
      <div className="row gap-sm">
        <button className="btn primary"><Icon name="sparkle"/> Auto-repair</button>
        <button className="btn ghost">Attach reference image</button>
        <button className="btn ghost">Dismiss</button>
      </div>
    </div>
  </div>
);

const CostTabView = ({ cost, packet }) => (
  <div className="col gap-md" style={{ maxWidth: 720 }}>
    <div className="card">
      <div className="card-title">This shot · estimate</div>
      <div className="cost-row"><span className="label">Provider · model</span><span className="v">seedance_2_0 / dreamina-seedance-2.0</span></div>
      <div className="cost-row"><span className="label">Route</span><span className="v">byteplus_modelark</span></div>
      <div className="cost-row"><span className="label">Duration · resolution</span><span className="v">{packet.duration_seconds}s · {packet.provider_params.resolution} · {packet.aspect_ratio}</span></div>
      <div className="cost-row"><span className="label">Mode</span><span className="v">{packet.provider_params.mode}</span></div>
      <div className="cost-row"><span className="label">Reference inputs</span><span className="v">0 image · 0 video · 0 audio</span></div>
      <div className="cost-row total"><span className="label">Estimated shot cost</span><span className="v">$2.95 USD</span></div>
    </div>
    <div className="card">
      <div className="card-title">Pricing basis</div>
      <div className="dim" style={{ fontSize: 11.5 }}>{cost.pricing_basis} · valid until {cost.valid_until} · refresh in approval step.</div>
    </div>
  </div>
);

const HistoryView = ({ history }) => (
  <div className="col gap-sm" style={{ maxWidth: 880 }}>
    {history.map((h, i) => (
      <div key={h.v} className="card" style={{ display: "grid", gridTemplateColumns: "60px 1fr 200px 100px", gap: 14, alignItems: "center" }}>
        <div className="serif" style={{ fontSize: 26, fontStyle: "italic", color: i === 0 ? "var(--accent)" : "var(--fg-faint)" }}>v{h.v}</div>
        <div>
          <div style={{ fontSize: 13 }}>{h.note}</div>
          <div className="mono dim" style={{ fontSize: 10, marginTop: 4 }}>{h.ts}</div>
        </div>
        <div>
          <div className="thumb-placeholder" data-label={`v${h.v} thumb`} style={{ position: "relative", height: 60, borderRadius: 3 }}/>
        </div>
        <div className="row gap-sm">
          {h.outcome === "current"
            ? <span className="tag accent">CURRENT</span>
            : <button className="btn ghost" style={{ fontSize: 11 }}>Restore</button>}
        </div>
      </div>
    ))}
  </div>
);

window.ScreenPrompts = ScreenPrompts;
