/* global React, ReactDOM */
/* App, state machine, and admin control bar. */

const { useState: useStateP, useEffect: useEffectP, useMemo: useMemoP } = React;

function shortRole(role) {
  return role
    .replace('Chief Executive Officer', 'CEO')
    .replace('Chief Technology Officer', 'CTO')
    .replace('Chief Financial Officer', 'CFO')
    .replace('Chief Operating Officer', 'COO')
    .replace('Chief Revenue Officer', 'CRO')
    .replace('Chief Product Officer', 'CPO')
    .replace('Chief Marketing Officer', 'CMO')
    .replace('Chief of Staff', 'CoS')
    .replace('VP, ', 'VP ');
}

// Admin control bar — visible only when ?admin=SECRET is in the URL.
function AdminBar({ me, stage, participants, submissions, votes, onSwitchPerson, onReset, onForceOpen, onForceClose, exportUrl }) {
  const filedCount = submissions ? Object.keys(submissions).length : 0;
  const votedCount = votes ? Object.keys(votes).length : 0;
  const total = participants.length;
  const pendingNames = participants
    .filter((p) => !submissions || !submissions[p.id])
    .map((p) => p.name.split(' ')[0]);
  return (
    <div className="demobar" data-testid="adminbar">
      <span className="tag">ADMIN</span>
      <span>brett.bruschke@gmail.com</span>

      <div className="group">
        <label>VIEW AS</label>
        <select value={me.id} onChange={(e) => onSwitchPerson(e.target.value)} data-testid="admin-as">
          {participants.map((p) => (
            <option key={p.id} value={p.id}>
              {p.name.split(' ')[0]} — {shortRole(p.role)}
            </option>
          ))}
        </select>
        <span style={{ color: '#8a8275', fontSize: 10 }}>· {stage}</span>
      </div>

      <div className="group" title={pendingNames.length ? `Pending: ${pendingNames.join(', ')}` : 'Everyone filed'} data-testid="admin-counts">
        <span style={{ color: '#c2b9a6' }}>{filedCount}<span style={{ color: '#8a8275' }}>/{total}</span> filed</span>
        <span style={{ color: '#3a342b' }}>·</span>
        <span style={{ color: '#c2b9a6' }}>{votedCount} voted</span>
      </div>

      <div className="group">
        <button onClick={onForceOpen} data-testid="admin-open">Force open vote</button>
        <button onClick={onForceClose} data-testid="admin-close">Force close + synthesize</button>
      </div>

      <div className="group">
        <a className="btn ghost" style={{ padding: '3px 7px', border: '1px solid #3a342b', color: '#f5f0e8', background: 'transparent', fontSize: 11 }} href={exportUrl} target="_blank" rel="noreferrer" data-testid="admin-export">Export JSON</a>
        <button className="primary" onClick={onReset} data-testid="admin-reset">Reset</button>
      </div>
    </div>
  );
}

// State machine — mirrors the server's evalVotingState plus per-user submission/vote checks.
function deriveStage(meId, participants) {
  const sub = window.storage.get('submission:' + meId);
  const vote = window.storage.get('vote:' + meId);
  const sg = window.storage.get('state:global') || {};
  const allSubmitted = participants.every((p) => window.storage.get('submission:' + p.id));
  const deadlinePassed = sg.deadlineISO && Date.now() >= new Date(sg.deadlineISO).getTime();
  const votingOpen = !!sg.votingForceOpen || allSubmitted || deadlinePassed;
  const votingClosed = !!sg.votingForceClosed || (votingOpen && sg.synthesis != null);

  if (votingClosed && sg.synthesis) return 'results';
  if (votingOpen && vote) return 'voted';
  if (votingOpen && sub) return 'voting';
  if (sub) return 'waiting';
  return 'intro';
}

function buildEntries() {
  const order = window.storage.get('anonymization:order', []);
  return order.map((pid, i) => {
    const sub = window.storage.get('submission:' + pid);
    return { id: `entry-${i + 1}`, pid, text: sub?.q4 || '(no submission)' };
  });
}

function App({ initialBoot }) {
  const [boot, setBoot] = useStateP(initialBoot);
  const [tick, setTick] = useStateP(0);
  const [uiBegin, setUiBegin] = useStateP(false);

  // Poll for state every 4s so multiple participants converge.
  useEffectP(() => {
    const t = setInterval(async () => {
      const fresh = await window.refreshState();
      if (fresh) setBoot(fresh);
      setTick((x) => x + 1);
    }, 4000);
    return () => clearInterval(t);
  }, []);

  // Local clock tick (countdown).
  useEffectP(() => {
    const t = setInterval(() => setTick((x) => x + 1), 1000);
    return () => clearInterval(t);
  }, []);

  const me = boot.me;
  const participants = boot.participants;
  const admin = !!boot.admin;

  // Expose PARTICIPANTS globally for helpers in data.jsx
  window.PARTICIPANTS = participants;

  const stage = useMemoP(() => deriveStage(me.id, participants), [me.id, tick]);

  useEffectP(() => { if (stage !== 'intro') setUiBegin(false); }, [stage]);

  const submissions = useMemoP(() => {
    const out = {};
    participants.forEach((p) => {
      const s = window.storage.get('submission:' + p.id);
      if (s) out[p.id] = s;
    });
    return out;
  }, [tick]);

  const votes = useMemoP(() => {
    const out = {};
    participants.forEach((p) => {
      const v = window.storage.get('vote:' + p.id);
      if (v) out[p.id] = v;
    });
    return out;
  }, [tick]);

  const stateGlobal = useMemoP(() => window.storage.get('state:global') || {}, [tick]);
  const entries = useMemoP(() => buildEntries(), [tick]);

  const onSubmit = async (data) => {
    await window.apiSubmit(data);
    const fresh = await window.refreshState();
    if (fresh) setBoot(fresh);
    setUiBegin(false);
    setTick((x) => x + 1);
    window.scrollTo({ top: 0, behavior: 'smooth' });
  };

  const onVote = async (votesObj) => {
    await window.apiVote(votesObj);
    const fresh = await window.refreshState();
    if (fresh) setBoot(fresh);
    setTick((x) => x + 1);
    window.scrollTo({ top: 0, behavior: 'smooth' });
  };

  const onSwitchPerson = (newId) => {
    const url = new URL(window.location.href);
    url.searchParams.set('admin', window.__MB_BOOT_CTX__.adminSecret);
    url.searchParams.set('as', newId);
    url.pathname = '/';
    window.location.href = url.toString();
  };

  const onReset = async () => {
    await window.apiAdminReset();
    const fresh = await window.refreshState();
    if (fresh) setBoot(fresh);
    setUiBegin(false);
    setTick((x) => x + 1);
  };

  const onForceOpen = async () => {
    await window.apiAdminForceOpen();
    const fresh = await window.refreshState();
    if (fresh) setBoot(fresh);
    setTick((x) => x + 1);
  };

  const onForceClose = async () => {
    await window.apiAdminForceClose();
    const fresh = await window.refreshState();
    if (fresh) setBoot(fresh);
    setTick((x) => x + 1);
  };

  const showSubmit = stage === 'submitting' || (stage === 'intro' && uiBegin);

  return (
    <>
      {admin && (
        <AdminBar
          me={me}
          stage={uiBegin && stage === 'intro' ? 'submitting' : stage}
          participants={participants}
          submissions={submissions}
          votes={votes}
          onSwitchPerson={onSwitchPerson}
          onReset={onReset}
          onForceOpen={onForceOpen}
          onForceClose={onForceClose}
          exportUrl={window.adminExportUrl()}
        />
      )}
      <div className="stage">
        <div className="sheet">
          <window.Masthead
            issueNum="001"
            dateStr={boot.masthead?.dateStr || 'Wed · May 20'}
            weather={boot.masthead?.weather || 'Springbrook · TX'}
          />

          {stage === 'intro' && !uiBegin && (
            <window.IntroScreen me={me} onBegin={() => setUiBegin(true)} />
          )}

          {showSubmit && (
            <window.SubmitScreen me={me} onSubmit={onSubmit} />
          )}

          {stage === 'waiting' && (
            <window.WaitingScreen
              me={me}
              participants={participants}
              submissions={submissions}
              deadlineISO={stateGlobal.deadlineISO}
            />
          )}

          {stage === 'voting' && (
            <window.VotingScreen me={me} entries={entries} onSubmit={onVote} />
          )}

          {stage === 'voted' && (
            <window.VotedScreen
              me={me}
              voteCount={Object.keys(votes).length}
              totalVoters={Object.keys(submissions).length}
            />
          )}

          {stage === 'results' && (
            <window.ResultsScreen
              entries={entries}
              votes={votes}
              submissions={submissions}
              synthesis={stateGlobal.synthesis || {}}
            />
          )}
        </div>
      </div>
    </>
  );
}

// Mount — fetch /api/state first, then render.
(async function bootstrap() {
  try {
    const boot = await window.refreshState();
    if (!boot) {
      document.getElementById('root').innerHTML =
        '<div style="padding:40px 22px;font-family:Inter,sans-serif;color:#c44d2a;text-align:center">Could not load. Check the URL.</div>';
      return;
    }
    ReactDOM.createRoot(document.getElementById('root')).render(<App initialBoot={boot} />);
  } catch (e) {
    console.error(e);
    document.getElementById('root').innerHTML =
      '<div style="padding:40px 22px;font-family:Inter,sans-serif;color:#c44d2a;text-align:center">Boot error: ' + (e.message || e) + '</div>';
  }
})();
