function SyncPanel() {
  const { sync, signInToSync, signOutOfSync, refreshFromCloud } = useStore();
  const [email, setEmail] = React.useState('');
  const [password, setPassword] = React.useState('');
  const [open, setOpen] = React.useState(false);

  async function submit(event) {
    event.preventDefault();
    if (!email.trim() || !password) return;
    try {
      await signInToSync(email.trim(), password);
      setPassword('');
    } catch (_) {}
  }

  function lastSyncedText(iso) {
    if (!iso) return '';
    const seconds = Math.max(0, Math.round((Date.now() - Date.parse(iso)) / 1000));
    if (seconds < 60) return `${seconds}s ago`;
    const minutes = Math.round(seconds / 60);
    if (minutes < 60) return `${minutes}m ago`;
    return `${Math.round(minutes / 60)}h ago`;
  }

  if (!sync.configured) {
    return (
      <div className="sync-panel">
        <div className="sync-help mono">DEPLOY TO USE DB</div>
      </div>
    );
  }

  return (
    <div className="sync-panel">
      <button className="sync-toggle" onClick={() => setOpen(value => !value)}>
        <span className={`sync-dot ${sync.signedIn ? 'on' : ''}`}></span>
        <span>{sync.signedIn ? sync.status : 'Sign in to sync'}</span>
      </button>

      {open && (
        <div className="sync-popover">
          {sync.signedIn ? (
            <div className="stack">
              <div className="mono muted">{sync.email}</div>
              <div className="sync-help">
                {sync.status}
                {sync.lastSyncedAt ? ` - last sync ${lastSyncedText(sync.lastSyncedAt)}` : ''}
              </div>
              {sync.error && <div className="sync-error">{sync.error}</div>}
              <div className="row">
                <button className="btn small" onClick={refreshFromCloud}>Refresh</button>
                <button className="btn small" onClick={signOutOfSync}>Sign out</button>
              </div>
            </div>
          ) : (
            <form onSubmit={submit} className="sync-form">
              <input className="input" type="email" placeholder="email" value={email} onChange={event => setEmail(event.target.value)} />
              <input className="input" type="password" placeholder="password" value={password} onChange={event => setPassword(event.target.value)} />
              <button className="btn primary" disabled={sync.pendingEmail}>{sync.pendingEmail ? 'Signing in...' : 'Sign in'}</button>
              {sync.error && <div className="sync-error">{sync.error}</div>}
              <div className="sync-help">Private sync uses the allowed email list configured in Cloudflare.</div>
            </form>
          )}
        </div>
      )}
    </div>
  );
}

function App() {
  const { state, update, sync } = useStore();
  const [menuOpen, setMenuOpen] = React.useState(false);
  const views = [
    { id: 'today', label: 'Today', pip: '01' },
    { id: 'calendar', label: 'Calendar', pip: '02' },
    { id: 'pending', label: 'Pending', pip: '03' },
    { id: 'rebuild', label: 'Rebuild', pip: '04' },
  ];
  const requested = new URLSearchParams(window.location.search).get('view');
  const view = views.some(item => item.id === requested) ? requested : (state.view || 'today');
  const activeView = views.find(item => item.id === view) || views[0];

  React.useEffect(() => {
    const bank = {
      topics: window.PLAN_DATA?.topics || [],
    };
    const fingerprint = rebuildFingerprint(bank);
    if (fingerprint && fingerprint !== state.rebuild?.bankFingerprint) {
      update(prev => syncBankIntoState(prev, bank));
    }
  }, [state.rebuild?.bankFingerprint, update]);

  function selectView(id) {
    if (window.location.search.includes('view=')) {
      window.history.replaceState(null, '', window.location.pathname + window.location.hash);
    }
    update({ view: id });
    setMenuOpen(false);
  }

  return (
    <div className="app">
      <aside className={`sidebar ${menuOpen ? 'menu-open' : ''}`}>
        <div className="brand">
          <div className="brand-title">Prep <span>OS</span><br />Python to Cloud</div>
          <div className="brand-sub">Jul 27 - Oct 25, 2026</div>
        </div>

        <div className="mobile-current">
          <span>Current</span>
          <strong>{activeView.label}</strong>
        </div>
        <button className="mobile-menu-btn" onClick={() => setMenuOpen(value => !value)}>
          {menuOpen ? 'Close' : 'Menu'}
        </button>

        <nav className="nav">
          {views.map(item => (
            <button
              key={item.id}
              className={`nav-item ${view === item.id ? 'active' : ''}`}
              onClick={() => selectView(item.id)}
            >
              <span>{item.label}</span>
              <span className="pip">{item.pip}</span>
            </button>
          ))}
        </nav>

        <div className="sidebar-foot">
          ACTIVE: JUL 27 - OCT 18<br />
          BUFFER: OCT 19 - OCT 25<br />
          DB ONLY - NO LOCAL SAVE
        </div>
        <SyncPanel />
      </aside>

      <main className="main">
        {!sync.signedIn ? (
          <div className="page">
            <div className="db-gate">
              <div className="kicker">Private DB Required</div>
              <h1 className="h-title">Sign in to load the tracker.</h1>
              <p className="copy">This Prep OS does not read from local storage and does not save browser-local progress. Sign in from the sidebar so Today, Calendar, Pending, and Rebuild all read and write Cloudflare D1-backed state.</p>
            </div>
          </div>
        ) : !sync.hydrated ? (
          <div className="page">
            <div className="db-gate">
              <div className="kicker">Loading DB</div>
              <h1 className="h-title">Reading Cloudflare state.</h1>
              <p className="copy">Please wait while the tracker loads the latest Today, Calendar, Pending, and Rebuild state from the database.</p>
            </div>
          </div>
        ) : (
          <>
            {view === 'today' && <TodayView />}
            {view === 'calendar' && <CalendarView />}
            {view === 'pending' && <PendingView />}
            {view === 'rebuild' && <RebuildView />}
          </>
        )}
      </main>
    </div>
  );
}

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