// app/app.jsx — root: onboarding gate, navigation, tab bar, theme + tweaks.
const { useState: useStateA, useEffect: useEffectA, useMemo: useMemoA, useRef: useRefA } = React;

const TABS = [
  { key: 'today', label: 'Today', icon: 'today' },
  { key: 'plan', label: 'Plan', icon: 'plan' },
  { key: 'progress', label: 'Progress', icon: 'progress' },
  { key: 'settings', label: 'Settings', icon: 'gear' },
];

function TabBar({ t, accent, font, active, onChange }) {
  return (
    <div style={{
      position: 'absolute', left: 0, right: 0, bottom: 0, zIndex: 40,
      padding: '8px 14px 26px', background: `linear-gradient(180deg, ${t.bg}00, ${t.bg} 38%)`,
      pointerEvents: 'none',
    }}>
      <div style={{
        pointerEvents: 'auto', background: t.surface, border: `1px solid ${t.line}`, borderRadius: 22,
        display: 'flex', padding: 6, boxShadow: t.dark ? '0 8px 24px rgba(0,0,0,0.4)' : '0 8px 26px rgba(22,36,63,0.14)',
      }}>
        {TABS.map(tab => {
          const on = active === tab.key;
          return (
            <button key={tab.key} onClick={() => onChange(tab.key)} className="bom-press" style={{
              flex: 1, border: 'none', background: on ? t.hero : 'transparent', cursor: 'pointer',
              borderRadius: 16, padding: '9px 4px 7px', display: 'flex', flexDirection: 'column',
              alignItems: 'center', gap: 4, fontFamily: 'inherit', transition: 'background 0.2s',
            }}>
              <span style={{ color: on ? accent.base : t.ink3, display: 'flex' }}>
                <Icon name={tab.icon} size={22} stroke={on ? 2.1 : 1.8} />
              </span>
              <span style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: '0.02em', color: on ? t.heroInk : t.ink3 }}>{tab.label}</span>
            </button>
          );
        })}
      </div>
    </div>
  );
}

function Placeholder({ t, font, name }) {
  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 10, color: t.ink3 }}>
      <Icon name="book" size={40} stroke={1.4} />
      <div style={{ fontFamily: font, fontSize: 20, color: t.ink2 }}>{name}</div>
      <div style={{ fontSize: 13 }}>Coming together…</div>
    </div>
  );
}

function App() {
  const [state, setState] = useStateA(window.loadState);
  const [tab, setTab] = useStateA(() => { try { return localStorage.getItem('bom_tab') || 'today'; } catch (e) { return 'today'; } });
  useEffectA(() => { try { localStorage.setItem('bom_tab', tab); } catch (e) {} }, [tab]);
  const [reader, setReader] = useStateA(null);   // { dayIdx, audio } when reading
  const [tw, setTweak] = window.useTweaks({
    theme: state.theme || 'royal',
    accent: state.accent || 'gold',
    font: state.font || 'serif',
  });

  // theme/accent/font — tweaks panel overrides saved state
  const themeKey = tw.theme || 'royal';
  const accentKey = tw.accent || 'gold';
  const t = window.THEMES[themeKey] || window.THEMES.royal;
  const accent = window.ACCENTS[accentKey] || window.ACCENTS.gold;
  const fontKey = tw.font || 'serif';
  const font = (window.FONTS[fontKey] || window.FONTS.serif).stack;

  // persist
  useEffectA(() => { window.saveState(state); }, [state]);

  // ── real cross-device sync ─────────────────────────────────────────────────
  const syncReady = useRefA(false);
  const pushTimer = useRefA(null);

  // on first run, mint a real CSPRNG sync code (replace the static placeholder)
  useEffectA(() => {
    if (window.BomSync && window.BomSync.isPlaceholder(state.syncCode)) {
      patch({ syncCode: window.BomSync.genCode() });
    }
  }, []);

  // pull + merge once the code is real
  useEffectA(() => {
    const code = state.syncCode;
    if (!window.BomSync || window.BomSync.isPlaceholder(code)) return;
    let cancelled = false;
    window.BomSync.pull(code)
      .then(remote => {
        if (!cancelled && remote) {
          const p = window.BomSync.merge(state, remote);
          if (p) setState(s => ({ ...s, ...p }));
        }
        syncReady.current = true;
      })
      .catch(() => { syncReady.current = true; });
    return () => { cancelled = true; };
  }, [state.syncCode]);

  // debounced push of every change, once the initial pull has settled
  useEffectA(() => {
    const code = state.syncCode;
    if (!window.BomSync || window.BomSync.isPlaceholder(code) || !syncReady.current) return;
    clearTimeout(pushTimer.current);
    pushTimer.current = setTimeout(() => { window.BomSync.push(code, state).catch(() => {}); }, 1200);
    return () => clearTimeout(pushTimer.current);
  }, [state]);

  // turning notifications on/off drives a real web-push subscription
  async function handleNotify(v) {
    patch({ notifyOn: v });
    if (!window.BomPush) return;
    if (v) {
      try {
        const r = await window.BomPush.enable(state.syncCode);
        if (!r.ok && (r.reason === 'denied' || r.reason === 'unsupported')) patch({ notifyOn: false });
      } catch (e) { patch({ notifyOn: false }); }
    } else {
      window.BomPush.disable(state.syncCode);
    }
  }

  // explicit "Sync now": push local, pull remote, merge
  async function syncNow() {
    const code = state.syncCode;
    if (!window.BomSync || window.BomSync.isPlaceholder(code)) throw new Error('no code');
    await window.BomSync.push(code, state);
    const remote = await window.BomSync.pull(code);
    if (remote) { const p = window.BomSync.merge(state, remote); if (p) setState(s => ({ ...s, ...p })); }
  }

  const plan = useMemoA(() => window.buildPlan({
    startDate: state.startDate, endDate: state.endDate, skipWeekdays: state.skipWeekdays || [],
  }), [state.startDate, state.endDate, JSON.stringify(state.skipWeekdays)]);

  const stats = useMemoA(() => window.planStats(plan, state.completed), [plan, state.completed]);

  function patch(p) { setState(s => ({ ...s, ...p })); }
  function toggleComplete(date) {
    setState(s => {
      const c = { ...s.completed };
      if (c[date]) delete c[date]; else c[date] = true;
      return { ...s, completed: c };
    });
  }

  function startPlan({ startDate, endDate, skipWeekdays }) {
    patch({ onboarded: true, startDate, endDate, skipWeekdays });
  }

  // body background
  const bg = themeKey === 'midnight' ? t.bg : t.bg;

  if (!state.onboarded) {
    return (
      <IOSDevice dark={t.dark}>
        <OnboardingScreen t={t} accent={accent} font={font} onStart={startPlan} />
      </IOSDevice>
    );
  }

  // reader overlay
  if (reader != null && window.ReaderScreen) {
    return (
      <IOSDevice dark={t.dark}>
        <div style={{ height: '100%', background: t.bg }}>
          <ReaderScreen
            t={t} accent={accent} font={font} fontScale={state.fontScale || 1}
            plan={plan} dayIdx={reader.dayIdx} startAudio={reader.audio}
            completed={state.completed} voice={state.voice} rate={state.rate}
            onClose={() => setReader(null)}
            onComplete={(date) => { if (!state.completed[date]) toggleComplete(date); }}
          />
        </div>
      </IOSDevice>
    );
  }

  let screen;
  if (tab === 'today') {
    screen = <TodayScreen t={t} accent={accent} font={font} plan={plan} completed={state.completed} stats={stats}
      onRead={(i) => setReader({ dayIdx: i, audio: false })} onListen={(i) => setReader({ dayIdx: i, audio: true })}
      encourageIdx={stats.done} />;
  } else if (tab === 'plan') {
    screen = window.PlanScreen
      ? <PlanScreen t={t} accent={accent} font={font} plan={plan} completed={state.completed} stats={stats}
          onOpen={(i) => setReader({ dayIdx: i, audio: false })} onToggle={toggleComplete} />
      : <Placeholder t={t} font={font} name="Reading Plan" />;
  } else if (tab === 'progress') {
    screen = window.ProgressScreen
      ? <ProgressScreen t={t} accent={accent} font={font} plan={plan} completed={state.completed} stats={stats} />
      : <Placeholder t={t} font={font} name="Progress" />;
  } else {
    screen = window.SettingsScreen
      ? <SettingsScreen t={t} accent={accent} font={font} state={state} patch={patch} plan={plan} stats={stats}
          themeKey={themeKey} accentKey={accentKey} onNotify={handleNotify} onSyncNow={syncNow} />
      : <Placeholder t={t} font={font} name="Settings" />;
  }

  return (
    <React.Fragment>
    <IOSDevice dark={t.dark}>
      <div style={{ height: '100%', background: t.bg, position: 'relative', display: 'flex', flexDirection: 'column' }}>
        <div style={{ flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column' }}>{screen}</div>
        <TabBar t={t} accent={accent} font={font} active={tab} onChange={setTab} />
      </div>
    </IOSDevice>
    <BomTweaks tw={tw} setTweak={setTweak} />
    </React.Fragment>
  );
}

// ── Tweaks panel: visual direction controls ──────────────────────────────────
function BomTweaks({ tw, setTweak }) {
  const { TweaksPanel, TweakSection, TweakRadio, TweakSelect } = window;
  if (!TweaksPanel) return null;
  return (
    <TweaksPanel title="Tweaks">
      <TweakSection title="Visual direction">
        <TweakSelect label="Theme" value={tw.theme}
          onChange={v => setTweak('theme', v)}
          options={Object.keys(window.THEMES).map(k => ({ value: k, label: window.THEMES[k].label }))} />
        <TweakSelect label="Accent" value={tw.accent}
          onChange={v => setTweak('accent', v)}
          options={window.ACCENT_ORDER.map(k => ({ value: k, label: window.ACCENTS[k].label }))} />
        <TweakRadio label="Reading face" value={tw.font}
          onChange={v => setTweak('font', v)}
          options={[{ value: 'serif', label: 'Spectral' }, { value: 'classic', label: 'Cormorant' }]} />
      </TweakSection>
    </TweaksPanel>
  );
}

window.App = App;
