/* global React */

// 16 Sep 2026 - the hue table and the gradient recipe live ONCE, on window (App.jsx).
const seqGradientModal = (n) => window.__seqGradient(window.__seqHue(n, (x) => 40 + (x*23) % 280));

const stageOf = (s) => {
  if (s.is_archive) return "archive";
  const st = s.stage_status || {};
  if (st.hero === "done") return "hero";
  if (st.refinement === "done" || (st.refinement === "pending" && st.first_pass === "done")) return "refinement";
  if (st.first_pass === "done") return "first-pass";
  if (st.prompt === "done") return "prompt";
  return "pending";
};
const STAGE_LABEL = {
  hero: "HERO", refinement: "REFINEMENT", "first-pass": "FIRST-PASS",
  prompt: "PROMPT", pending: "PENDING", archive: "ARCHIVE",
};
const STAGE_COLOR = {
  hero: "var(--leaf)", refinement: "var(--amber)", "first-pass": "var(--teal)",
  prompt: "var(--tan)", pending: "var(--ink-soft)", archive: "var(--archive)",
};

function SequenceDetailModal({ sequence, shots = [], onClose, onOpenShot }) {
  React.useEffect(() => {
    if (!sequence) return;
    const onKey = (e) => { if (e.key === "Escape") onClose && onClose(); };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [sequence, onClose]);

  // v970 — omitted (cut) shots are HIDDEN here by default (Hugo: "in sequences,
  // dont show me the omitted shots, and have a button to show them"). Declared
  // above the `if (!sequence) return null` guard so the hook count never changes.
  const [showOmitted, setShowOmitted] = React.useState(false);
  React.useEffect(() => { setShowOmitted(false); }, [sequence && sequence.number]);
  // v07zz362 — pick which shot's frame represents this sequence on its card.
  const canSetCover = !!(window.hasPerm && window.hasPerm("manage_episodes"));
  const setCover = async (shotId, e) => {
    if (e) e.stopPropagation();
    if (!sequence) return;
    try {
      await (window.authFetch || fetch)(`/api/sequences/${sequence.number}`, {
        method: "PATCH", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ cover_shot_id: shotId, episode_id: sequence.episode_id }), // v07zz425 — target the right episode
      });
      if (window.reloadAppData) window.reloadAppData();
    } catch (_) {}
  };

  // v07zz389 — inline-edit the rich scene description: the "continuous moment" blurb
  // the Generate page uses as the default for this sequence's shot/grid prompts.
  const canEditDesc = canSetCover;
  const [editingDesc, setEditingDesc] = React.useState(false);
  const [descDraft, setDescDraft] = React.useState("");
  const saveDesc = async () => {
    setEditingDesc(false);
    const v = (descDraft || "").trim();
    if (!sequence || v === String(sequence.scene_description || "").trim()) return;
    try {
      await (window.authFetch || fetch)(`/api/sequences/${sequence.number}`, {
        method: "PATCH", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ scene_description: v, episode_id: sequence.episode_id }), // v07zz425 — target the right episode
      });
      if (window.reloadAppData) window.reloadAppData();
    } catch (_) {}
  };

  if (!sequence) return null;
  const allSeqShots = shots.filter(s => s.seq === sequence.number);
  const omittedCount = allSeqShots.filter(s => s.omitted).length;
  const seqShots = showOmitted ? allSeqShots : allSeqShots.filter(s => !s.omitted);
  const heroDone = seqShots.filter(s => s.stage_status && s.stage_status.hero === "done").length;
  const fpDone = seqShots.filter(s => s.stage_status && s.stage_status.first_pass === "done").length;
  const pct = seqShots.length ? Math.round((fpDone / seqShots.length) * 100) : 0;

  return (
    <div className="modal-backdrop sequence-backdrop" onClick={onClose}>
      <div className="sequence-modal glass" onClick={e => e.stopPropagation()}>
        <button className="modal-close" onClick={onClose} aria-label="Close">
          <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round"><path d="M5 5l14 14M19 5L5 19"/></svg>
        </button>

        <div className="sm-head">
          <div className="sm-eyebrow">SEQUENCE {String(sequence.number).padStart(2,"0")}</div>
          <div className="sm-title">{sequence.slug}</div>
          <div className="sm-meta">
            <span>{seqShots.length} shots</span>
            {omittedCount > 0 && (
              <button type="button" className="sm-omit-toggle"
                title={showOmitted
                  ? "Hide the cut shots again"
                  : "Show the " + omittedCount + " cut shot" + (omittedCount === 1 ? "" : "s") + " in this sequence"}
                onClick={() => setShowOmitted(v => !v)}>
                {showOmitted ? "Hide " : "Show "}{omittedCount} cut
              </button>
            )}
          </div>
          {/* v07zz389 — editable scene description: the default "continuous moment" for generation prompts. */}
          <div className="sm-scene">
            <div className="sm-scene-label">SCENE — used as the default for generation prompts</div>
            {editingDesc ? (
              <textarea className="sm-scene-edit" autoFocus value={descDraft}
                placeholder="Describe the continuous moment of this sequence — who, where, when, and what happens…"
                onChange={(e) => setDescDraft(e.target.value)}
                onBlur={saveDesc}
                onKeyDown={(e) => { if (e.key === "Escape") { e.preventDefault(); setEditingDesc(false); } else if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { e.preventDefault(); saveDesc(); } }} />
            ) : (
              <div className={"sm-scene-text" + (sequence.scene_description ? "" : " is-empty") + (canEditDesc ? " is-editable" : "")}
                onClick={canEditDesc ? () => { setDescDraft(sequence.scene_description || ""); setEditingDesc(true); } : undefined}
                title={canEditDesc ? "Click to edit — this is the default scene description used in shot & grid prompts (⌘/Ctrl+Enter to save)" : undefined}>
                {sequence.scene_description || (canEditDesc ? "+ Add a scene description (used as the default for generation prompts)" : "—")}
              </div>
            )}
          </div>
          <div className="sm-progress">
            <div className="sm-progress-fill" style={{width: `${pct}%`}}/>
          </div>
        </div>

        <div className="sequence-grid">
          {seqShots.length === 0 && (
            <div className="sm-empty">No shots seeded for this sequence in the demo dataset.</div>
          )}
          {seqShots.map(shot => {
            const stage = stageOf(shot);
            // v01j — pull thumbnail from the shot's image_paths.selected
            // (preferred) or .first_pass, mirroring ShotsPanel's ShotThumb
            // logic so the sequence grid matches what the shots list shows.
            const img = shot.image_paths && (shot.image_paths.selected || shot.image_paths.first_pass);
            return (
              // v970 — a cut shot is only on screen when Show-cut is on; dim it and
              // badge it so it never reads as a live shot.
              <button key={shot.id} className={"sequence-shot-tile" + (shot.omitted ? " is-omitted" : "")}
                onClick={(e) => { e.stopPropagation(); onOpenShot && onOpenShot(shot.id); /* v04d — DO NOT close sequence here; let it stay open so closing the shot returns to it. */ }}>
                <div className="sst-thumb" style={{background: seqGradientModal(shot.seq)}}>
                  {/* v07zz31 — Mipmap. 4-column grid → ~200 px tile width.
                      Width-400 covers 2× retina; previously the modal
                      loaded N full-res renders on every open. */}
                  {img && <img className="sst-img" src={window.thumbUrl ? window.thumbUrl(img, 400) : img} alt={shot.id} loading="lazy"/>}
                  <span className="sst-pill" style={{background: STAGE_COLOR[stage]}}>{STAGE_LABEL[stage]}</span>
                  {shot.omitted && <span className="sst-cut-badge" title="This shot is cut from the edit">CUT</span>}
                  {shot.id === sequence.cover_shot_id && <span className="sst-cover-badge" title="Sequence cover">★ COVER</span>}
                  {canSetCover && shot.id !== sequence.cover_shot_id && (
                    <button type="button" className="sst-cover-btn" title="Use this shot as the sequence cover"
                      onClick={(e) => setCover(shot.id, e)}>Set cover</button>
                  )}
                  <div className="tile-overlay">
                    <div className="sst-id">{shot.id}</div>
                    <div className="sst-frame">{shot.frame_title}</div>
                  </div>
                </div>
              </button>
            );
          })}
        </div>

        <div className="sm-foot">
          {seqShots.length} shots · {fpDone} first-pass done · {heroDone} hero selected
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { SequenceDetailModal });
