// Mean It — Spine, Drafting, Render screens.

// ─────────── SPINE + STRUCTURE ───────────

function Spine({ go, setEmotion, auto }) {
  const [pick, setPick] = React.useState(null);
  const [cursorPos, setCursorPos] = React.useState({ x: 0, y: 0 });
  const [cursorVisible, setCursorVisible] = React.useState(false);
  const [clicking, setClicking] = React.useState(false);
  const [callout, setCallout] = React.useState(null);

  const phraseRefs = React.useRef([]);
  const startRef = React.useRef(null);

  React.useEffect(() => { setEmotion('moved'); }, []);

  React.useEffect(() => {
    if (!auto) return;
    let cancelled = false;
    const wait = (ms) => new Promise(r => setTimeout(r, ms));
    const moveTo = (el, opts = {}) => {
      if (!el) return;
      const r = el.getBoundingClientRect();
      setCursorPos({
        x: r.left + (opts.offsetX != null ? opts.offsetX : r.width / 2),
        y: r.top + (opts.offsetY != null ? opts.offsetY : r.height / 2),
      });
    };
    const calloutAbove = (el, msg) => {
      if (!el) return;
      const r = el.getBoundingClientRect();
      setCallout({ x: r.left + r.width / 2, y: r.top, text: msg });
    };

    (async () => {
      setCursorPos({ x: window.innerWidth * 0.7, y: 200 });
      setCursorVisible(true);
      await wait(700);
      if (cancelled) return;

      // pick the first phrase (the one marked picked: true in SCRIPT)
      const target = phraseRefs.current[0];
      calloutAbove(target, 'pick the heart of this letter');
      moveTo(target, { offsetY: 60 });
      await wait(2000);
      if (cancelled) return;
      setClicking(true);
      await wait(220);
      if (cancelled) return;
      setPick(0);
      await wait(380);
      setClicking(false);
      setCallout(null);

      await wait(900);
      if (cancelled) return;
      calloutAbove(startRef.current, 'start writing');
      moveTo(startRef.current);
      await wait(1500);
      if (cancelled) return;
      setClicking(true);
      await wait(280);
      if (cancelled) return;
      go();
    })();

    return () => { cancelled = true; };
  }, [auto]);

  return (
    <div className="stage">
      <div className="eyebrow">spine · the line everything else hangs from</div>
      <h1 className="h-display smaller" style={{ marginTop: 8, marginBottom: 8 }}>
        Three of your phrases.<br/>One of them is the heart.
      </h1>
      <div className="body-prose" style={{ maxWidth: 580, marginBottom: 28 }}>
        Every phrase below is your verbatim text. Pick the one this letter is built around.
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: 14 }}>
        {SCRIPT.spineCandidates.map((p, i) => (
          <button key={i}
            ref={el => phraseRefs.current[i] = el}
            onClick={() => setPick(i)}
            className={'card ' + (pick === i ? 'selected' : 'outlined')}
            style={{ textAlign: 'left', cursor: 'pointer', padding: '20px 22px',
                     fontFamily: 'inherit', color: 'inherit', minHeight: 200,
                     display: 'flex', flexDirection: 'column', justifyContent: 'space-between' }}>
            <div>
              <div className="eyebrow">phrase 0{i+1}</div>
              <div className="serif-italic" style={{ fontSize: 22, lineHeight: 1.3, marginTop: 10, color: 'var(--t-ink)' }}>
                "{p.t}"
              </div>
            </div>
            <div className="muted" style={{ fontFamily: 'var(--t-mono)', fontSize: 10, marginTop: 16 }}>
              {pick === i ? '● this is the spine' : 'from · ' + p.from}
            </div>
          </button>
        ))}
      </div>

      <div className="divider-flourish"/>

      <div className="eyebrow" style={{ marginBottom: 12 }}>structure the guide proposes — three movements</div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 14 }}>
        {SCRIPT.structure.map((s, i) => (
          <div key={i} className="card outlined" style={{ padding: '18px 22px' }}>
            <div className="eyebrow" style={{ color: 'var(--t-accent)' }}>movement {i+1}</div>
            <div className="serif-italic" style={{ fontSize: 22, marginTop: 6, color: 'var(--t-ink)' }}>{s.label}</div>
            <div className="muted" style={{ fontFamily: 'var(--t-mono)', fontSize: 10, marginTop: 4 }}>{s.sub}</div>
            <div style={{
              marginTop: 16, padding: '14px 12px',
              border: '1px dashed var(--t-ink-faint)', borderRadius: 'var(--t-radius)',
              fontFamily: 'var(--t-mono)', fontSize: 10, color: 'var(--t-ink-faint)',
              textAlign: 'center', letterSpacing: '0.1em', textTransform: 'uppercase',
            }}>your words · go here</div>
          </div>
        ))}
      </div>

      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 36 }}>
        <span className="muted" style={{ fontFamily: 'var(--t-mono)', fontSize: 11 }}>swap or drop any movement · this is yours</span>
        <button ref={startRef} className="btn primary" onClick={go} disabled={pick === null} style={{ opacity: pick === null ? 0.4 : 1 }}>start writing →</button>
      </div>

      {auto && cursorVisible && <VirtualCursor x={cursorPos.x} y={cursorPos.y} clicking={clicking}/>}
      {auto && callout && <TourCallout x={callout.x} y={callout.y} text={callout.text}/>}
    </div>
  );
}

// ─────────── DRAFTING (streaming critique, A) ───────────

function Drafting({ go, setEmotion, auto }) {
  const [text, setText] = React.useState('');
  const [critiques, setCritiques] = React.useState([]);
  const target = SCRIPT.draft.map(d => d.text).join('\n');
  const [step, setStep] = React.useState(0);
  const [cutIndices, setCutIndices] = React.useState([]);

  const [cursorPos, setCursorPos] = React.useState({ x: 0, y: 0 });
  const [cursorVisible, setCursorVisible] = React.useState(false);
  const [clicking, setClicking] = React.useState(false);
  const [callout, setCallout] = React.useState(null);

  const cutBtnRef = React.useRef(null);
  const renderBtnRef = React.useRef(null);

  React.useEffect(() => { setEmotion('listening'); }, []);

  React.useEffect(() => {
    if (!auto || step < target.length) return;
    let cancelled = false;
    const wait = (ms) => new Promise(r => setTimeout(r, ms));
    const moveTo = (el, opts = {}) => {
      if (!el) return;
      const r = el.getBoundingClientRect();
      setCursorPos({
        x: r.left + (opts.offsetX != null ? opts.offsetX : r.width / 2),
        y: r.top + (opts.offsetY != null ? opts.offsetY : r.height / 2),
      });
    };
    const calloutAbove = (el, msg) => {
      if (!el) return;
      const r = el.getBoundingClientRect();
      setCallout({ x: r.left + r.width / 2, y: r.top, text: msg });
    };

    (async () => {
      await wait(900);
      if (cancelled) return;

      // cursor enters near the right side
      setCursorPos({ x: window.innerWidth * 0.7, y: window.innerHeight * 0.5 });
      setCursorVisible(true);
      await wait(450);
      if (cancelled) return;

      // cut the cliché
      if (cutBtnRef.current) {
        calloutAbove(cutBtnRef.current, "this one isn't yours · cut it");
        moveTo(cutBtnRef.current);
        await wait(2000);
        if (cancelled) return;
        setClicking(true);
        await wait(220);
        if (cancelled) return;
        const cIdx = SCRIPT.draft.findIndex(d => d.flag === 'cliche');
        setCutIndices(s => [...s, cIdx]);
        await wait(380);
        setClicking(false);
        setCallout(null);
      }

      await wait(1100);
      if (cancelled) return;

      // render the artifact
      calloutAbove(renderBtnRef.current, 'render the artifact');
      moveTo(renderBtnRef.current);
      await wait(1500);
      if (cancelled) return;
      setClicking(true);
      await wait(300);
      if (cancelled) return;
      go();
    })();

    return () => { cancelled = true; };
  }, [auto, step, target.length]);

  // simulate typing on mount
  React.useEffect(() => {
    if (step >= target.length) return;
    const t = setTimeout(() => {
      setText(target.slice(0, step + 1));
      setStep(step + 1);
      // mood beats while typing
      const ch = target[step];
      if (ch === '\n') {
        const lineIdx = target.slice(0, step).split('\n').length - 1;
        const line = SCRIPT.draft[lineIdx];
        if (line) {
          if (line.flag === 'cliche') {
            setEmotion('sad');
            setCritiques(c => [...c, {
              kind: 'cliche', line: line.text,
              note: 'this one is borrowed. you noticed a notebook of strangers\' names — keep going specific.',
            }]);
          } else if (line.verified) {
            setEmotion('moved');
            setCritiques(c => [...c, {
              kind: 'verified', line: line.text,
              note: 'verified yours · from ' + line.src,
            }]);
          }
        }
      }
    }, 18);
    return () => clearTimeout(t);
  }, [step]);

  const lines = text.split('\n');
  const bylinePct = Math.round(
    (SCRIPT.draft.slice(0, lines.length).filter(d => d.verified).length / Math.max(lines.length, 1)) * 100
  );

  return (
    <div className="stage" style={{ maxWidth: 1180 }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 22 }}>
        <div className="eyebrow">drafting · streaming critique</div>
        <div className="byline">
          <span className="byline-dot"/>
          <span>{bylinePct}% verified yours · {lines.length} / {SCRIPT.draft.length} lines</span>
        </div>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1.5fr 1fr', gap: 48 }}>
        {/* LEFT — draft */}
        <div>
          <div className="eyebrow" style={{ marginBottom: 12 }}>your letter · for tomas</div>
          <div className="card outlined" style={{
            padding: '32px 36px', minHeight: 380,
            fontFamily: 'var(--t-body)', fontSize: 19, lineHeight: 1.75,
            color: 'var(--t-ink)',
          }}>
            {lines.map((ln, i) => {
              const meta = SCRIPT.draft[i];
              const flagged = meta && meta.flag === 'cliche';
              const cut = cutIndices.includes(i);
              return (
                <div key={i} style={{
                  background: cut ? 'transparent' : (flagged ? 'var(--t-accent-soft)' : 'transparent'),
                  textDecoration: cut ? 'line-through' : (flagged ? 'underline wavy var(--t-accent)' : 'none'),
                  opacity: cut ? 0.3 : 1,
                  borderRadius: 2, padding: '0 2px',
                  transition: 'opacity 280ms ease',
                }}>
                  {ln || <span style={{ opacity: 0.3 }}>·</span>}
                </div>
              );
            })}
            <span style={{
              display: 'inline-block', width: 1.5, height: 20, background: 'var(--t-ink)',
              animation: 'blink 1s infinite', verticalAlign: 'middle',
            }}/>
          </div>
        </div>

        {/* RIGHT — critique stream */}
        <div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 12 }}>
            <MascotView id={SCRIPT.mascot} emotion={critiques.find(c=>c.kind==='cliche') ? 'sad' : 'listening'} size={48}/>
            <div className="eyebrow">guide · just notes</div>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 12, maxHeight: 460, overflow: 'auto' }} className="no-scrollbar">
            {critiques
              .filter(c => {
                if (c.kind !== 'cliche') return true;
                const idx = SCRIPT.draft.findIndex(d => d.text === c.line);
                return !cutIndices.includes(idx);
              })
              .slice().reverse().map((c, i) => (
              <div key={i} className="card outlined" style={{
                padding: '12px 16px',
                borderColor: c.kind === 'cliche' ? 'var(--t-accent)' : 'var(--t-ink-ghost)',
                borderLeft: '2px solid ' + (c.kind === 'cliche' ? 'var(--t-accent)' : 'var(--t-verified)'),
                animation: 'fadein 400ms ease',
              }}>
                <div className="eyebrow" style={{ color: c.kind === 'cliche' ? 'var(--t-accent)' : 'var(--t-verified)' }}>
                  {c.kind === 'cliche' ? '⚠ cliché · borrowed phrase' : '✓ verified yours'}
                </div>
                <div style={{ fontFamily: 'var(--t-body)', fontSize: 14, marginTop: 6, color: 'var(--t-ink-soft)', lineHeight: 1.5 }}>
                  {c.note}
                </div>
                {c.kind === 'cliche' && (
                  <div style={{ display: 'flex', gap: 8, marginTop: 10 }}>
                    <button ref={cutBtnRef} className="btn ghost sm" onClick={() => {
                      const idx = SCRIPT.draft.findIndex(d => d.text === c.line);
                      setCutIndices(s => s.includes(idx) ? s : [...s, idx]);
                    }}>cut it</button>
                    <button className="btn ghost sm">i'll keep it</button>
                  </div>
                )}
              </div>
            ))}
            {critiques.length === 0 && (
              <div className="muted" style={{ fontFamily: 'var(--t-mono)', fontSize: 11, padding: 12 }}>
                listening as you write…
              </div>
            )}
          </div>
        </div>
      </div>

      <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: 28 }}>
        <button ref={renderBtnRef} className="btn primary" onClick={go}>render the artifact →</button>
      </div>

      {auto && cursorVisible && <VirtualCursor x={cursorPos.x} y={cursorPos.y} clicking={clicking}/>}
      {auto && callout && <TourCallout x={callout.x} y={callout.y} text={callout.text}/>}
    </div>
  );
}

// ─────────── RENDER + HOVER TRACE ───────────

function Render({ openDownload, openSave, openShare, openStartOver, openReel, setEmotion, auto, restart, modalOpen }) {
  const [hovered, setHovered] = React.useState(null);
  const [pos, setPos] = React.useState({ x: 0, y: 0 });

  const [cursorPos, setCursorPos] = React.useState({ x: 0, y: 0 });
  const [cursorVisible, setCursorVisible] = React.useState(false);
  const [clicking, setClicking] = React.useState(false);
  const [callout, setCallout] = React.useState(null);

  const downloadRef = React.useRef(null);
  const saveRef = React.useRef(null);
  const shareRef = React.useRef(null);
  const reelRef = React.useRef(null);

  React.useEffect(() => { setEmotion('hopeful'); }, []);

  React.useEffect(() => {
    if (!auto) return;
    let cancelled = false;
    const wait = (ms) => new Promise(r => setTimeout(r, ms));
    const moveTo = (el, opts = {}) => {
      if (!el) return;
      const r = el.getBoundingClientRect();
      setCursorPos({
        x: r.left + (opts.offsetX != null ? opts.offsetX : r.width / 2),
        y: r.top + (opts.offsetY != null ? opts.offsetY : r.height / 2),
      });
    };
    const calloutAbove = (el, msg) => {
      if (!el) return;
      const r = el.getBoundingClientRect();
      setCallout({ x: r.left + r.width / 2, y: r.top, text: msg });
    };
    const clickButton = async (ref, msg, openFn) => {
      if (!ref.current) return;
      calloutAbove(ref.current, msg);
      moveTo(ref.current);
      await wait(1500);
      if (cancelled) return;
      setClicking(true);
      await wait(220);
      if (cancelled) return;
      setCursorVisible(false);
      setCallout(null);
      openFn();
      await wait(220);
      setClicking(false);
    };

    (async () => {
      // settle on the artifact
      await wait(1400);
      if (cancelled) return;

      setCursorPos({ x: window.innerWidth * 0.7, y: window.innerHeight * 0.5 });
      setCursorVisible(true);
      await wait(500);
      if (cancelled) return;

      // 1. download → image card → close
      await clickButton(downloadRef, 'take it with you', openDownload);
      await wait(15500);
      if (cancelled) return;
      setCursorVisible(true);

      // 2. save
      await clickButton(saveRef, 'keep it in your library', openSave);
      await wait(7000);
      if (cancelled) return;
      setCursorVisible(true);

      // 3. share trace
      await clickButton(shareRef, 'share — proof attached', openShare);
      await wait(8500);
      if (cancelled) return;
      setCursorVisible(true);

      // 4. make a reel
      await clickButton(reelRef, 'make it move', openReel);
      await wait(16500);
      if (cancelled) return;

      // restart
      setCursorVisible(false);
      await wait(1500);
      if (cancelled) return;
      if (restart) restart();
    })();

    return () => { cancelled = true; };
  }, [auto]);

  // skip the cliché line — user "cut it"
  const finalLines = SCRIPT.draft.filter(d => d.verified);
  const total = finalLines.reduce((n, d) => n + d.text.split(/\s+/).length, 0);
  const verified = total; // 100% after cut

  const lineToQuestion = (src) => SCRIPT.interview.find((_, i) => 'q' + (i+1) === src);

  return (
    <div className="stage" style={{ maxWidth: 760, paddingTop: 64 }}>
      {/* postmark — top right of the artifact */}
      <div className="corner-stamp">
        <div className="postmark">
          <div className="pm-top">verified · yours</div>
          <div className="pm-mid">100%</div>
          <div className="pm-bot">mean it · 2025</div>
        </div>
      </div>

      <div style={{ textAlign: 'center', marginBottom: 36 }}>
        <div className="eyebrow">for tomas · read aloud, saturday</div>
        <div className="ornament" style={{ marginTop: 12 }}>
          <svg width="120" height="14" viewBox="0 0 120 14" style={{ display: 'inline' }}>
            <path d="M 4 7 Q 30 2, 60 7 T 116 7" stroke="currentColor" strokeWidth="1" fill="none"/>
            <circle cx="60" cy="7" r="2" fill="currentColor"/>
          </svg>
        </div>
      </div>

      <article style={{
        fontFamily: 'var(--t-body)',
        fontSize: 24,
        lineHeight: 1.75,
        textAlign: 'center',
        color: 'var(--t-ink)',
      }}>
        {finalLines.map((ln, i) => {
          const q = lineToQuestion(ln.src);
          return (
            <div key={i}
              className="trace-line"
              style={{ marginBottom: i === finalLines.length - 2 ? 18 : 4 }}
              onMouseEnter={e => { setHovered({ ln, q }); setPos({ x: e.clientX, y: e.clientY }); }}
              onMouseMove={e => setPos({ x: e.clientX, y: e.clientY })}
              onMouseLeave={() => setHovered(null)}
            >
              {ln.text}
            </div>
          );
        })}
      </article>

      <div className="divider-flourish" style={{ marginTop: 64 }}>
        <span className="ornament-glyph">❦</span>
      </div>

      <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', gap: 14, marginBottom: 8 }}>
        <div className="seal" style={{ width: 44, height: 44 }}>
          <span className="seal-glyph" style={{ fontSize: 18 }}>M</span>
        </div>
        <div className="serif-italic" style={{ fontSize: 22, color: 'var(--t-ink)' }}>
          One hundred percent your words.
        </div>
      </div>
      <div className="muted" style={{ fontFamily: 'var(--t-mono)', fontSize: 10, textAlign: 'center', letterSpacing: '0.14em' }}>
        every line · hover · see the question that prompted it
      </div>

      <div style={{ display: 'flex', justifyContent: 'center', gap: 10, marginTop: 28, flexWrap: 'wrap' }}>
        <button ref={downloadRef} className="btn ghost sm" onClick={openDownload}>↓ download</button>
        <button ref={saveRef} className="btn ghost sm" onClick={openSave}>♡ save</button>
        <button ref={shareRef} className="btn ghost sm" onClick={openShare}>↗ share trace</button>
        <button className="btn sm" onClick={openStartOver}>start over</button>
      </div>

      {/* MAKE IT MOVE — featured CTA */}
      <div className="divider-flourish" style={{ marginTop: 36 }}><span className="ornament-glyph">·</span></div>
      <div className="card raised" style={{
        marginTop: 8, padding: '22px 26px',
        display: 'grid', gridTemplateColumns: '1fr auto', gap: 24, alignItems: 'center',
        background: 'var(--t-paper-warm)', position: 'relative', overflow: 'hidden',
      }}>
        {/* tiny phone-frame accent */}
        <div style={{ position: 'absolute', top: -10, right: 130, transform: 'rotate(6deg)', opacity: 0.85 }}>
          <div style={{
            width: 46, height: 84, borderRadius: 8,
            border: '2px solid var(--t-ink)',
            background: 'linear-gradient(155deg, color-mix(in srgb, var(--t-accent) 50%, var(--t-paper)), var(--t-paper-warm))',
            position: 'relative',
          }}>
            <div style={{ position: 'absolute', left: '50%', top: 4, transform: 'translateX(-50%)', width: 12, height: 2, background: 'var(--t-ink)', borderRadius: 1 }}/>
            <div style={{ position: 'absolute', left: 4, right: 4, bottom: 6, fontFamily: 'var(--t-display)', fontStyle: 'italic', fontSize: 5.5, lineHeight: 1.1, color: 'var(--t-ink)', textAlign: 'center' }}>
              "the world is wide…"
            </div>
          </div>
        </div>
        <div>
          <div className="eyebrow accent">new · for letters that should be seen</div>
          <h3 className="serif-italic" style={{ fontSize: 28, color: 'var(--t-ink)', marginTop: 6, marginBottom: 6, fontStyle: 'italic' }}>
            Make it move.
          </h3>
          <div className="body-prose" style={{ fontSize: 14, maxWidth: 540 }}>
            Turn this letter into a 30-second reel. Drop in photos, read it aloud in your voice, and we'll cut it to 9:16 — captions, your audio, and the trace badge on the end card.
          </div>
        </div>
        <button ref={reelRef} className="btn primary" onClick={openReel} style={{ whiteSpace: 'nowrap' }}>
          ▶ make a reel
        </button>
      </div>

      {hovered && (
        <div className="trace-pop" style={{
          left: Math.min(pos.x + 16, window.innerWidth - 340),
          top: Math.max(pos.y - 100, 20),
        }}>
          <div className="eyebrow" style={{ color: 'var(--t-accent)' }}>trace · {hovered.ln.src}</div>
          <div className="muted" style={{ fontFamily: 'var(--t-mono)', fontSize: 9, marginTop: 8 }}>question</div>
          <div className="serif-italic" style={{ fontSize: 14, marginTop: 2, color: 'var(--t-ink)' }}>
            "{hovered.q?.q}"
          </div>
          <div className="muted" style={{ fontFamily: 'var(--t-mono)', fontSize: 9, marginTop: 10 }}>your verbatim answer</div>
          <div style={{ fontSize: 13, marginTop: 4, color: 'var(--t-ink-soft)', fontStyle: 'italic' }}>
            "{hovered.q?.a}"
          </div>
          <div style={{
            marginTop: 12, paddingTop: 10, borderTop: '1px solid var(--t-ink-ghost)',
            fontFamily: 'var(--t-mono)', fontSize: 9, color: 'var(--t-verified)', letterSpacing: '0.1em', textTransform: 'uppercase',
          }}>✓ exact substring · verified yours</div>
        </div>
      )}

      {auto && cursorVisible && !modalOpen && <VirtualCursor x={cursorPos.x} y={cursorPos.y} clicking={clicking}/>}
      {auto && callout && !modalOpen && <TourCallout x={callout.x} y={callout.y} text={callout.text}/>}
    </div>
  );
}

Object.assign(window, { Spine, Drafting, Render });
