// Main app
// Depends on: everything

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "density": "comfortable"
}/*EDITMODE-END*/;

function TweaksPanel({ open, onClose, values, onChange }) {
  if (!open) return null;
  return (
    <div className="tweaks">
      <div className="tweaks-header">
        <div className="tiny">tweaks · display</div>
        <button className="btn btn-sm btn-ghost" onClick={onClose}>close</button>
      </div>

      <div className="micro" style={{ textTransform: 'none', letterSpacing: 0, color: 'var(--ink-3)', lineHeight: 1.45, marginBottom: 14 }}>
        conversation style (voice, asymmetry, directness) lives in <b>phase 00</b> and is co-signed by both parties. these tweaks only affect how this view renders for you.
      </div>

      <div>
        <div className="tiny mb-2">density</div>
        {[
          { v: 'comfortable', l: 'comfortable' },
          { v: 'compact', l: 'compact' },
        ].map(o => (
          <div
            key={o.v}
            className={`seat-chip ${values.density === o.v ? 'active' : ''}`}
            style={{ display: 'flex', marginBottom: 4, border: '1px solid var(--rule)' }}
            onClick={() => onChange({ density: o.v })}
          >{o.l}</div>
        ))}
      </div>
    </div>
  );
}

class PhaseErrorBoundary extends React.Component {
  constructor(props) { super(props); this.state = { error: null }; }
  static getDerivedStateFromError(error) { return { error }; }
  componentDidCatch(error, info) {
    console.error('PHASE CRASH', this.props.phase, error, info.componentStack);
  }
  render() {
    if (this.state.error) {
      return (
        <div style={{ padding: 30, fontFamily: 'monospace', fontSize: 12, lineHeight: 1.5 }}>
          <div style={{ fontSize: 16, marginBottom: 12, color: '#c44' }}>crash in phase: {this.props.phase}</div>
          <div style={{ whiteSpace: 'pre-wrap', background: '#faf7f2', padding: 12, border: '1px dashed #ccc' }}>
            {this.state.error.message}
            {"\n\n"}
            {this.state.error.stack}
          </div>
          <button style={{ marginTop: 12 }} onClick={() => { localStorage.setItem('cg_phase', 'topic'); location.reload(); }}>
            reset
          </button>
        </div>
      );
    }
    return this.props.children;
  }
}

function StyleGate({ onGo }) {
  return (
    <div style={{ padding: '60px 40px', maxWidth: 720, margin: '0 auto' }}>
      <div className="tiny" style={{ marginBottom: 6 }}>phase 01 · topic lock</div>
      <h1 style={{ marginTop: 4, fontFamily: 'var(--font-prose)', fontWeight: 500 }}>
        set the tone first.
      </h1>
      <p style={{ color: 'var(--ink-2)', maxWidth: 600, lineHeight: 1.55, marginTop: 10 }}>
        before any topic drafting, both parties pick and co-sign the session\u2019s conversation style. this shapes every agent\u2019s voice for the rest of the session and can\u2019t be edited mid-argument.
      </p>
      <button className="btn btn-primary mt-3" onClick={onGo}>
        <Icons.Arrow size={10} /> go to phase 00 \u00b7 style
      </button>
    </div>
  );
}

function App() {
  const [phase, setPhase] = React.useState(() => {
    const saved = localStorage.getItem('cg_phase');
    const liveMode = CG.hasKey && CG.hasKey() && CG.getMode && CG.getMode() === 'fresh';
    if (liveMode) {
      // Default to style in live mode until style is locked. Once locked, allow saved phase.
      const styleLocked = CG.session && CG.session.isStyleLocked && CG.session.isStyleLocked();
      if (!styleLocked) return 'style';
      if (!saved) return 'topic';
    }
    return saved || 'topic';
  });
  // Seat: 'A' or 'B'. Coerce any legacy 'god' value.
  const [seat, setSeat] = React.useState(() => {
    const s = localStorage.getItem('cg_seat');
    return (s === 'A' || s === 'B') ? s : 'A';
  });
  const [tweaks, setTweaks] = React.useState(TWEAK_DEFAULTS);
  const [tweaksOpen, setTweaksOpen] = React.useState(false);
  const [claudeModalOpen, setClaudeModalOpen] = React.useState(false);
  const [roomModalOpen, setRoomModalOpen] = React.useState(false);

  // When in multiplayer, lock seat to session seat
  const [, forceSess] = React.useState(0);
  React.useEffect(() => {
    const u1 = CG.peer.onStatus(() => forceSess(t => t + 1));
    const u2 = CG.session.onState(() => forceSess(t => t + 1));
    const u3 = CG.onStatus(() => forceSess(t => t + 1));
    return () => { u1(); u2(); u3(); };
  }, []);
  const sessionSeat = CG.session.getSeat();
  React.useEffect(() => {
    if (sessionSeat && sessionSeat !== seat) setSeat(sessionSeat);
  }, [sessionSeat]);

  React.useEffect(() => { localStorage.setItem('cg_phase', phase); }, [phase]);
  React.useEffect(() => { localStorage.setItem('cg_seat', seat); }, [seat]);

  // Reset phase when a hard reset fires (new room, start fresh, etc.)
  React.useEffect(() => {
    const handler = () => setPhase('style');
    window.addEventListener('cg:reset', handler);
    return () => window.removeEventListener('cg:reset', handler);
  }, []);

  // Broadcast this user's current phase to the partner via shared.cursor[seat].phase.
  // Purely presence — nobody is forced to follow anyone.
  React.useEffect(() => {
    if (!CG.session.isMultiplayer || !CG.session.isMultiplayer()) return;
    const mySeat = CG.session.getSeat();
    if (!mySeat) return;
    try {
      const cur = (CG.session.shared && CG.session.shared.cursor) || {};
      CG.session.setShared({ cursor: { ...cur, [mySeat]: { ...(cur[mySeat] || {}), phase } } });
    } catch (e) {}
  }, [phase, sessionSeat]);

  // Tweaks edit-mode protocol
  React.useEffect(() => {
    const handler = (e) => {
      if (e.data?.type === '__activate_edit_mode') setTweaksOpen(true);
      if (e.data?.type === '__deactivate_edit_mode') setTweaksOpen(false);
    };
    window.addEventListener('message', handler);
    window.parent.postMessage({ type: '__edit_mode_available' }, '*');
    return () => window.removeEventListener('message', handler);
  }, []);

  const updateTweaks = (patch) => {
    const next = { ...tweaks, ...patch };
    setTweaks(next);
    window.parent.postMessage({ type: '__edit_mode_set_keys', edits: patch }, '*');
  };

  // Temperature rough mapping to phase — removed along with the top-bar gauge.

  // Live-mode routing: every phase is Claude-backed. Topic (01) is blocked until style (00) is co-signed.
  const liveMode = (CG.hasKey() && CG.getMode() === 'fresh') || !!(CG.session && CG.session.isGuest && CG.session.isGuest());
  const styleLocked = CG.session && CG.session.isStyleLocked && CG.session.isStyleLocked();
  const showStyleGate = liveMode && phase === 'topic' && !styleLocked;

  const PhaseView = {
    style: StyleLockPhase,
    topic: TopicLockPhase,
    intake: liveMode && window.LiveIntakePhase ? window.LiveIntakePhase : IntakePhase,
    opening: liveMode && window.LiveOpeningPhase ? window.LiveOpeningPhase : OpeningPhase,
    steelman: liveMode && window.LiveSteelmanPhase ? window.LiveSteelmanPhase : SteelmanPhase,
    room: liveMode && window.LiveRoomPhase ? window.LiveRoomPhase : RoomPhase,
    callout: CalloutPhase,
    apology: liveMode && window.LiveApologyPhase ? window.LiveApologyPhase : ApologyPhase,
    artifact: liveMode && window.LiveArtifactPhase ? window.LiveArtifactPhase : ArtifactPhase,
  }[phase] || TopicLockPhase;

  return (
    <div data-screen-label={`Clarguments · ${phase}`} style={{ height: '100vh', display: 'flex', flexDirection: 'column' }} className="paper-bg">
      <TopBar
        phase={phase}
        onPhase={setPhase}
        seat={seat}
        onConnectClaude={() => setClaudeModalOpen(true)}
        onOpenRoom={() => setRoomModalOpen(true)}
        onPause={() => alert('paused · state saved · each party gets a private "where we left off" note')}
      />
      <DisconnectBanner />
      <ClaudeModal open={claudeModalOpen} onClose={() => setClaudeModalOpen(false)} />
      <RoomModal open={roomModalOpen} onClose={() => setRoomModalOpen(false)} />

      <div style={{ display: 'flex', flex: 1, minHeight: 0 }}>
        <div style={{ flex: 1, overflow: 'auto', position: 'relative' }}>
          <div key={phase + seat} className="ink-in" style={{ minHeight: '100%' }}>
            <PhaseErrorBoundary phase={phase}>
              {showStyleGate
                ? <StyleGate onGo={() => setPhase('style')} />
                : <PhaseView seat={seat} godView={false} onPhase={setPhase} />}
            </PhaseErrorBoundary>
          </div>
        </div>
      </div>

      <TweaksPanel
        open={tweaksOpen}
        onClose={() => setTweaksOpen(false)}
        values={tweaks}
        onChange={updateTweaks}
      />

      {/* Coach's ledger · private floating drawer */}
      {phase !== 'style' && phase !== 'topic' && <CoachLedgerDrawer seat={seat} />}

      {window.CG_VERSION && (
        <div style={{
          position: 'fixed', bottom: 8, right: 10,
          fontFamily: 'JetBrains Mono, monospace', fontSize: 10,
          color: 'rgba(0,0,0,0.25)', pointerEvents: 'none', userSelect: 'none',
          zIndex: 9999,
        }}>
          {window.CG_VERSION}
        </div>
      )}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
