// Phase 03 · LIVE blind opening + mediator synthesis.
//
// State machine (drawn on shared.openings[seat]):
//   step 'draft'    → party is writing raw draft. visible only to them.
//   step 'review'   → coach has returned neutralized_draft + red_flags. party reviews/edits.
//   step 'submitted'→ party has committed a submission. waiting for partner.
//   step 'approve'  → both submitted; mediator has returned syntheses. party must approve theirs.
//   step 'posted'   → party approved; their synthesis is now in shared.openings[seat].synthesis.
//
// shared.openings[seat] shape (live mode):
//   { _intakeSubmitted, good_outcome,  // carried from phase 02
//     step, submitted, synthesis, approved, framing }
//
// Host drives the mediator synth call once both sides are 'submitted'. Results go into
// shared.openings[A|B].synthesis + shared.openings.framing. Guest sees the same via session
// state sync.
//
// The raw draft is NEVER written to shared state. It lives only in local React state +
// (optionally) the party's private thread. The submitted text is party-approved.

(function () {
  const { useState, useEffect, useRef } = React;

  window.LiveOpeningPhase = function LiveOpeningPhase({ seat, onPhase }) {
    const [, tick] = useState(0);
    useEffect(() => CG.session.onState(() => tick(t => t + 1)), []);

    const shared = CG.session.shared || {};
    const names = (CG.session.getNames && CG.session.getNames()) || {};
    const mp = CG.session.isMultiplayer && CG.session.isMultiplayer();
    const isHost = !mp || seat === 'A';
    const otherSeat = seat === 'A' ? 'B' : 'A';
    const myName = names[seat] || (seat === 'A' ? 'host' : 'guest');
    const otherName = names[otherSeat] || (otherSeat === 'A' ? 'host' : 'guest');
    const goodOutcome = shared.openings?.[seat]?.good_outcome || null;

    const mine = shared.openings?.[seat] || {};
    const theirs = shared.openings?.[otherSeat] || {};
    const myStep = mine.step || 'draft';
    const theirStep = theirs.step || 'draft';

    // Presence: map opening step → activity label
    useEffect(() => {
      const map = {
        draft: 'writing raw draft',
        review: 'reviewing with coach',
        submitted: `waiting on ${otherName}`,
        approve: 'approving synthesis',
        posted: theirStep === 'posted' ? 'both posted' : `waiting on ${otherName}`,
      };
      const activity = map[myStep] || 'drafting';
      try { CG.session.setCursor && CG.session.setCursor({ activity }); } catch (e) {}
    }, [myStep, theirStep, otherName]);

    // local-only draft text
    const [raw, setRaw] = useState('');
    const [neutralized, setNeutralized] = useState('');
    const [editable, setEditable] = useState(''); // the actively-editable version shown in review
    const [redFlags, setRedFlags] = useState([]);
    const [coachMsg, setCoachMsg] = useState('');
    const [reviewing, setReviewing] = useState(false);
    const [error, setError] = useState('');
    const [synthError, setSynthError] = useState('');
    const [synthesizing, setSynthesizing] = useState(false);
    const synthRunningRef = useRef(false);

    // Persist raw across reloads locally (never shared).
    useEffect(() => {
      (async () => {
        const saved = await CG.store.get(`opening_raw_${seat}`);
        if (saved && typeof saved === 'string') setRaw(saved);
      })();
    }, [seat]);
    useEffect(() => {
      CG.store.set(`opening_raw_${seat}`, raw);
    }, [raw, seat]);

    // --- actions ---

    const patchMine = (patch) => {
      // Read from the live session object, not the React render snapshot — avoids overwriting
      // the partner's state when both sides write openings at nearly the same time.
      const currentOpenings = CG.session.shared?.openings || {};
      const updatedMine = { ...(currentOpenings[seat] || {}), ...patch };
      CG.session.setShared({ openings: { ...currentOpenings, [seat]: updatedMine } });
    };

    const requestReview = async () => {
      const text = raw.trim();
      if (!text || reviewing) return;
      setReviewing(true);
      setError('');
      try {
        const r = await CG.agents.openingCoach.review(seat, text);
        setNeutralized(r.neutralized_draft);
        setEditable(r.neutralized_draft || text);
        setRedFlags(r.red_flags || []);
        setCoachMsg(r.message || '');
        patchMine({ step: 'review' });
      } catch (e) {
        setError(String(e.message || e));
      } finally {
        setReviewing(false);
      }
    };

    const submitOpening = () => {
      const text = (editable || '').trim();
      if (!text) return;
      patchMine({ step: 'submitted', submitted: text });
    };

    // Reset back to draft (e.g. change my mind)
    const resetToDraft = () => {
      patchMine({ step: 'draft', submitted: null });
    };

    // Approve my own synthesis → post it.
    const approveMine = () => {
      patchMine({ step: 'posted', approved: true });
    };

    // --- host-only: run mediator synth when both submitted ---
    const bothSubmitted = mine.step === 'submitted' || mine.step === 'approve' || mine.step === 'posted';
    const partnerSubmitted = theirs.step === 'submitted' || theirs.step === 'approve' || theirs.step === 'posted';
    const needsSynth = isHost
      && (mine.step === 'submitted')
      && (theirs.step === 'submitted')
      && !shared.openings?.framing;

    useEffect(() => {
      if (!needsSynth || synthRunningRef.current) return;
      let cancelled = false;
      synthRunningRef.current = true;
      const openingsSnapshot = shared.openings;
      (async () => {
        setSynthesizing(true);
        setSynthError('');
        try {
          const submittedA = openingsSnapshot?.A?.submitted || '';
          const submittedB = openingsSnapshot?.B?.submitted || '';
          if (!submittedA || !submittedB) return;
          const r = await CG.agents.mediatorSynth.synthesize(submittedA, submittedB);
          if (cancelled) return;
          // Re-read live state after the async call so we don't overwrite any changes
          // that arrived while the mediator was running.
          const liveOpenings = CG.session.shared?.openings || {};
          const openings = {
            ...liveOpenings,
            A: { ...(liveOpenings.A || {}), synthesis: r.synthesis_A, step: 'approve' },
            B: { ...(liveOpenings.B || {}), synthesis: r.synthesis_B, step: 'approve' },
            framing: r.framing,
          };
          CG.session.setShared({ openings });
        } catch (e) {
          if (!cancelled) setSynthError(String(e.message || e));
        } finally {
          synthRunningRef.current = false;
          if (!cancelled) setSynthesizing(false);
        }
      })();
      return () => { cancelled = true; synthRunningRef.current = false; };
    }, [needsSynth]);

    // --- solo fallback: simulate the partner in solo mode ---
    // In solo, the partner doesn't exist. We auto-fill their submission with a placeholder
    // so the user can walk through the full flow end-to-end. This is clearly labeled.
    useEffect(() => {
      if (mp) return;
      if (mine.step !== 'submitted') return;
      if (theirs.step === 'submitted' || theirs.step === 'approve' || theirs.step === 'posted') return;
      const openings = { ...(shared.openings || {}) };
      openings[otherSeat] = {
        ...(openings[otherSeat] || {}),
        step: 'submitted',
        submitted: `(solo mode · ${otherName} did not participate. the mediator will proceed with a placeholder opening so you can see the full flow.)`,
      };
      CG.session.setShared({ openings });
    }, [mp, mine.step, theirs.step]);

    // --- render ---

    return (
      <div style={{ padding: '22px 40px 60px', maxWidth: 1180, margin: '0 auto' }}>
        <div className="tiny">phase 03 · blind opening + synthesis · live</div>
        <h1 style={{ marginTop: 6, marginBottom: 6 }}>
          say it once, in your own words. the mediator speaks you back in neutral.
        </h1>
        <p style={{ maxWidth: 720, color: 'var(--ink-2)', marginBottom: 14, lineHeight: 1.5 }}>
          write what you want {otherName} to hear first. your coach will soften the edges without changing what you're saying.
          neither of you sees the other's draft until both submit.{' '}
          <span className="hand" style={{ color: 'var(--blue)' }}>
            then the mediator rewrites each opening for the other side, and you sign off on yours before it posts.
          </span>
        </p>

        {goodOutcome && (
          <div className="paper-card p-3" style={{ background: 'var(--paper-2)', marginBottom: 16 }}>
            <div className="tiny mb-1">your anchor · from intake</div>
            <div className="hand" style={{ fontSize: '1.15rem', color: 'var(--blue)', lineHeight: 1.25 }}>
              "{goodOutcome}"
            </div>
          </div>
        )}

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 320px', gap: 18 }}>
          {/* LEFT — the writing surface, which changes by step */}
          <div className="paper-card p-4">
            <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 10 }}>
              <div className="tiny">your opening · {myName}</div>
              <AgentBadge agent={seat === 'B' ? 'coachB' : 'coachA'} />
            </div>

            {myStep === 'draft' && (
              <DraftStep
                raw={raw}
                setRaw={setRaw}
                onReview={requestReview}
                reviewing={reviewing}
                error={error}
                otherName={otherName}
              />
            )}

            {myStep === 'review' && (
              <ReviewStep
                raw={raw}
                neutralized={neutralized}
                editable={editable}
                setEditable={setEditable}
                redFlags={redFlags}
                coachMsg={coachMsg}
                onBack={() => patchMine({ step: 'draft' })}
                onSubmit={submitOpening}
              />
            )}

            {myStep === 'submitted' && (
              <SubmittedStep
                submitted={mine.submitted}
                partnerSubmitted={partnerSubmitted}
                onReset={resetToDraft}
                synthesizing={synthesizing}
                synthError={synthError}
                otherName={otherName}
              />
            )}

            {(myStep === 'approve' || myStep === 'posted') && (
              <SynthesisStep
                mine={mine}
                theirs={theirs}
                framing={shared.openings?.framing}
                otherName={otherName}
                myName={myName}
                otherSeat={otherSeat}
                onApprove={approveMine}
                onPhase={onPhase}
              />
            )}
          </div>

          {/* RIGHT — partner status + continue gate */}
          <div>
            <PartnerPanel
              mp={mp}
              otherName={otherName}
              theirStep={theirStep}
              myStep={myStep}
            />

            <div className="paper-card p-3 mt-3" style={{
              background: mine.step === 'posted' && theirs.step === 'posted' ? 'var(--green-soft)' : 'var(--paper-2)',
              borderLeft: `2px solid ${mine.step === 'posted' && theirs.step === 'posted' ? 'var(--green)' : 'var(--rule)'}`,
            }}>
              <div className="tiny mb-2">continue</div>
              {mine.step === 'posted' && theirs.step === 'posted'
                ? <button className="btn btn-sm btn-primary" onClick={() => onPhase && onPhase('steelman')}>
                    → phase 04 · steel-man gate <Icons.Arrow size={10} />
                  </button>
                : <div className="mono" style={{ fontSize: '0.72rem', color: 'var(--ink-3)' }}>
                    {mine.step !== 'posted' ? 'your synthesis isn\'t approved yet.' : `waiting on ${otherName}.`}
                  </div>}
            </div>
          </div>
        </div>
      </div>
    );
  };

  // --- sub-steps ---

  function DraftStep({ raw, setRaw, onReview, reviewing, error, otherName }) {
    return (
      <div>
        <div className="tiny mb-2">step 1 · your raw draft · nobody else sees this yet</div>
        <div className="micro mb-2" style={{ textTransform: 'none', letterSpacing: 0, color: 'var(--ink-3)', lineHeight: 1.5 }}>
          say what you actually want {otherName} to hear. no self-editing yet. the coach will soften the edges in a second.
        </div>
        <textarea
          className="paper-input"
          rows={8}
          placeholder={`if ${otherName} were going to hear ONE opening from you, what would it be?`}
          value={raw}
          onChange={e => setRaw(e.target.value)}
          disabled={reviewing}
        />
        <div style={{ display: 'flex', gap: 8, marginTop: 10, alignItems: 'center' }}>
          <button
            className="btn btn-sm btn-primary"
            disabled={!raw.trim() || reviewing}
            onClick={onReview}
          >{reviewing ? 'coach reading…' : 'coach · review my draft'}</button>
          <div style={{ flex: 1 }} />
          <span className="mono" style={{ fontSize: '0.7rem', color: 'var(--ink-3)' }}>
            {raw.trim().split(/\s+/).filter(Boolean).length} words
          </span>
        </div>
        {reviewing && (
          <div className="paper-card p-3 mt-3 ink-in" style={{ background: 'var(--paper-2)' }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
              <div className="micro">coach · softening the edges</div>
              <ThinkingInk label="looking for characterizations vs. specifics…" />
            </div>
            <SkelLines lines={3} widths={['100%', '94%', '68%']} />
            <div className="dashed" style={{ margin: '10px 0' }} />
            <div className="micro mb-2">red flags</div>
            <SkelLines lines={2} widths={['80%', '55%']} />
          </div>
        )}
        {error && (
          <div className="paper-card p-2 mt-3" style={{ background: 'var(--red-soft)', borderLeft: '2px solid var(--red)' }}>
            <div className="micro" style={{ color: 'var(--red)' }}>error</div>
            <div style={{ fontSize: '0.85rem' }}>{error}</div>
          </div>
        )}
      </div>
    );
  }

  function ReviewStep({ raw, neutralized, editable, setEditable, redFlags, coachMsg, onBack, onSubmit }) {
    return (
      <div>
        <div className="tiny mb-2">step 2 · coach review · edit freely</div>
        {coachMsg && (
          <div className="paper-card p-2 mb-3" style={{ background: 'var(--paper-2)', borderLeft: '2px solid var(--ink-3)' }}>
            <div className="micro mb-1">coach</div>
            <div style={{ fontSize: '0.9rem', lineHeight: 1.4 }}>{coachMsg}</div>
          </div>
        )}

        {redFlags.length > 0 && (
          <div style={{ marginBottom: 12 }}>
            <div className="micro mb-2" style={{ textTransform: 'none', letterSpacing: 0, color: 'var(--ink-3)' }}>
              things the coach flagged in your raw draft · <i>private</i>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              {redFlags.map((f, i) => (
                <div key={i} style={{ fontSize: '0.82rem', padding: '6px 10px', borderLeft: '2px solid oklch(55% 0.18 30)', background: 'var(--paper-2)' }}>
                  <div className="mono" style={{ fontSize: '0.62rem', color: 'var(--ink-3)', letterSpacing: '0.05em', textTransform: 'uppercase', marginBottom: 2 }}>
                    {f.kind}
                  </div>
                  <div style={{ fontStyle: 'italic', marginBottom: 3 }}>"{f.quote}"</div>
                  <div style={{ color: 'var(--ink-2)', lineHeight: 1.35 }}>{f.reason}</div>
                </div>
              ))}
            </div>
          </div>
        )}

        <div className="tiny mb-2">suggested version · edit before submitting</div>
        <textarea
          className="paper-input"
          rows={8}
          value={editable}
          onChange={e => setEditable(e.target.value)}
        />

        <details style={{ marginTop: 10 }}>
          <summary className="mono" style={{ fontSize: '0.72rem', color: 'var(--ink-3)', cursor: 'pointer' }}>
            show my original raw draft
          </summary>
          <div className="paper-card p-2 mt-2" style={{ background: 'var(--paper-3)', fontSize: '0.85rem', whiteSpace: 'pre-wrap', lineHeight: 1.5 }}>
            {raw}
          </div>
        </details>

        <div style={{ display: 'flex', gap: 8, marginTop: 14 }}>
          <button className="btn btn-sm" onClick={onBack}>← back to draft</button>
          <button className="btn btn-sm btn-primary" disabled={!editable.trim()} onClick={onSubmit}>
            submit · nobody else sees your text yet
          </button>
        </div>
      </div>
    );
  }

  function SubmittedStep({ submitted, partnerSubmitted, onReset, synthesizing, synthError, otherName }) {
    return (
      <div>
        <div className="tiny mb-2">step 3 · submitted · held until partner submits</div>
        <div className="paper-card p-3" style={{ background: 'var(--paper-2)' }}>
          <div className="micro mb-2">your submitted opening · sealed</div>
          <div style={{ fontSize: '0.95rem', lineHeight: 1.55, whiteSpace: 'pre-wrap' }}>{submitted}</div>
        </div>

        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 14 }}>
          <span className="stamp stamp-green" style={{ fontSize: '0.6rem' }}>submitted</span>
          {partnerSubmitted
            ? (synthesizing
                ? <span className="mono" style={{ fontSize: '0.72rem' }}>mediator is synthesizing…</span>
                : <span className="mono" style={{ fontSize: '0.72rem' }}>both submitted · preparing synthesis</span>)
            : <span className="mono" style={{ fontSize: '0.72rem', color: 'var(--ink-3)' }}>waiting on {otherName}…</span>}
          <div style={{ flex: 1 }} />
          <button
            className="btn btn-sm"
            onClick={onReset}
            disabled={partnerSubmitted}
            title={partnerSubmitted ? `${otherName} has already submitted — you can't retract now` : 'go back and rewrite your opening'}
          >
            change my mind
          </button>
        </div>

        {synthesizing && (
          <div className="paper-card p-3 mt-3 ink-in" style={{ background: 'var(--paper-2)' }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
              <div className="micro">mediator's voicing of your opening</div>
              <AgentBadge agent="mediator" />
            </div>
            <div style={{ marginBottom: 10 }}>
              <ThinkingInk label="re-voicing both openings in neutral…" />
            </div>
            <SkelLines lines={4} widths={['100%', '96%', '92%', '70%']} />
          </div>
        )}

        {partnerSubmitted && (
          <div className="mono mt-2" style={{ fontSize: '0.72rem', color: 'var(--ink-3)' }}>
            {otherName} has submitted — retracting isn't possible now.
          </div>
        )}

        {synthError && (
          <div className="paper-card p-2 mt-3" style={{ background: 'var(--red-soft)', borderLeft: '2px solid var(--red)' }}>
            <div className="micro" style={{ color: 'var(--red)' }}>synthesis error</div>
            <div style={{ fontSize: '0.85rem' }}>{synthError}</div>
          </div>
        )}
      </div>
    );
  }

  function SynthesisStep({ mine, theirs, framing, otherName, myName, otherSeat, onApprove, onPhase }) {
    const approved = mine.step === 'posted';
    const theirApproved = theirs.step === 'posted';
    return (
      <div>
        <div className="tiny mb-2">step 4 · mediator synthesis · approve your own</div>
        {framing && (
          <div className="hand mb-3" style={{ fontSize: '1.1rem', color: 'var(--blue)', lineHeight: 1.3 }}>
            "{framing}"
          </div>
        )}

        <div className="paper-card p-3" style={{ background: 'var(--paper-2)', position: 'relative' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
            <div className="micro">mediator's voicing of YOUR opening</div>
            <AgentBadge agent="mediator" />
          </div>
          <div style={{ fontSize: '0.95rem', lineHeight: 1.55, whiteSpace: 'pre-wrap' }}>{mine.synthesis || '—'}</div>
          <details style={{ marginTop: 10 }}>
            <summary className="mono" style={{ fontSize: '0.72rem', color: 'var(--ink-3)', cursor: 'pointer' }}>
              show what i actually submitted
            </summary>
            <div className="paper-card p-2 mt-2" style={{ background: 'var(--paper-3)', fontSize: '0.85rem', whiteSpace: 'pre-wrap', lineHeight: 1.5 }}>
              {mine.submitted}
            </div>
          </details>
          {!approved && (
            <div style={{ display: 'flex', gap: 8, marginTop: 12 }}>
              <button className="btn btn-sm btn-primary" onClick={onApprove}>
                approve · post to the room
              </button>
              <span className="mono" style={{ fontSize: '0.7rem', color: 'var(--ink-3)', alignSelf: 'center' }}>
                you control whether this goes up.
              </span>
            </div>
          )}
          {approved && (
            <div style={{ marginTop: 12, display: 'flex', flexDirection: 'column', gap: 8 }}>
              <span className="stamp stamp-green" style={{ fontSize: '0.6rem' }}>{myName} approved · posted</span>
              {!theirApproved && (
                <div style={{ padding: '7px 9px', background: 'var(--paper-2)', borderLeft: '2px solid var(--ink-3)', fontSize: '0.8rem', color: 'var(--ink-2)' }}>
                  waiting on {otherName} to approve their synthesis.
                </div>
              )}
            </div>
          )}
        </div>

        {/* Partner's synthesis — shown but labeled as their side */}
        <div className="paper-card p-3 mt-3" style={{
          background: 'var(--paper-2)',
          opacity: theirApproved ? 1 : 0.7,
        }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
            <div className="micro">mediator's voicing of {otherName}'s opening</div>
            {theirApproved
              ? <span className="stamp stamp-green" style={{ fontSize: '0.58rem' }}>posted</span>
              : <span className="mono" style={{ fontSize: '0.66rem', color: 'var(--ink-3)' }}>awaiting {otherName}'s approval…</span>}
          </div>
          <div style={{ fontSize: '0.95rem', lineHeight: 1.55, whiteSpace: 'pre-wrap' }}>{theirs.synthesis || '—'}</div>
        </div>
      </div>
    );
  }

  function PartnerPanel({ mp, otherName, theirStep, myStep }) {
    const stepOrder = ['draft', 'review', 'submitted', 'approve', 'posted'];
    const theyAreAhead = mp && stepOrder.indexOf(theirStep) > stepOrder.indexOf(myStep);

    const label = (() => {
      switch (theirStep) {
        case 'draft':     return 'drafting…';
        case 'review':    return 'reviewing with coach…';
        case 'submitted': return 'submitted · sealed';
        case 'approve':   return 'approving synthesis…';
        case 'posted':    return 'posted';
        default:          return 'drafting…';
      }
    })();
    return (
      <div className="paper-card p-3" style={{ position: 'sticky', top: 10 }}>
        <div className="tiny mb-2">{otherName}'s room · firewalled</div>
        <div style={{
          minHeight: 90,
          background: 'repeating-linear-gradient(135deg, transparent 0 8px, var(--paper-3) 8px 9px)',
          padding: 12, marginBottom: 10,
        }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 6 }}>
            <Icons.Lock size={11} /><span className="micro">sealed</span>
          </div>
          <div className="hand" style={{ fontSize: '0.95rem', color: 'var(--ink-3)', lineHeight: 1.3 }}>
            you only see which step they're on.
          </div>
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <span className="mono" style={{ fontSize: '0.7rem', color: 'var(--ink-3)' }}>status</span>
          {theirStep === 'submitted' || theirStep === 'approve' || theirStep === 'posted'
            ? <span className="stamp stamp-green" style={{ fontSize: '0.6rem' }}>{label}</span>
            : <span className="mono" style={{ fontSize: '0.7rem' }}>{mp ? label : 'solo · simulated'}</span>}
        </div>
        {theyAreAhead && (
          <div style={{ marginTop: 10, padding: '7px 9px', background: 'oklch(96% 0.04 240)', borderLeft: '2px solid var(--blue)', fontSize: '0.8rem', color: 'var(--ink-2)', lineHeight: 1.4 }}>
            {otherName} is ahead — they're waiting on you.
          </div>
        )}
      </div>
    );
  }

  console.log('[phases-opening-live] loaded');
})();
