/* app.jsx — 路由 + 外壳 + Tweaks */

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "direction": "B",
  "palette": "绿松石",
  "grain": true
}/*EDITMODE-END*/;

/* 调色方案：每套都改写整组 CSS 变量，而不只是一个色值 */
const PALETTES = {
  '墨青': { ink: '#0b2426', t900: '#0c3f44', t800: '#12545a', t700: '#17696e', t500: '#01999a', t300: '#7fc4c2', gold: '#c09a5e', goldDeep: '#a67f42', goldPale: '#e6d5b6', cloud: '#f7f9f8', cloud2: '#eef3f2', txt: '#16302f', txt2: '#4c6564', txt3: '#7d9190', line: '12,63,68' },
  /* 绿松石 · 默认：结构与墨青一致，主色换成 Tiffany / 绿松石蓝 */
  '绿松石': { ink: '#07282b', t900: '#0b3d44', t800: '#115159', t700: '#196a71', t500: '#33a9ab', t300: '#93d3d1', gold: '#c09a5e', goldDeep: '#a67f42', goldPale: '#e6d5b6', cloud: '#f6fafa', cloud2: '#e8f2f2', txt: '#122e30', txt2: '#456466', txt3: '#7b9597', line: '11,61,68' },
  '暮紫': { ink: '#1e1530', t900: '#33254f', t800: '#443266', t700: '#56407d', t500: '#8a6ac2', t300: '#c4b1e2', gold: '#c9a46b', goldDeep: '#a8844c', goldPale: '#ecdcc2', cloud: '#f8f7fa', cloud2: '#efecf4', txt: '#231a33', txt2: '#5a4f6c', txt3: '#8a8199', line: '51,37,79' },
  '暖砂': { ink: '#2a1f17', t900: '#4a3423', t800: '#5e432e', t700: '#7a5638', t500: '#b07a45', t300: '#dcbb92', gold: '#5f8a7a', goldDeep: '#456e5f', goldPale: '#c8dcd3', cloud: '#faf7f3', cloud2: '#f2ece4', txt: '#2e241c', txt2: '#665747', txt3: '#998877', line: '74,52,35' },
};

function applyPalette(name) {
  const p = PALETTES[name] || PALETTES['墨青'];
  const r = document.documentElement.style;
  r.setProperty('--ink', p.ink);
  r.setProperty('--teal-900', p.t900);
  r.setProperty('--teal-800', p.t800);
  r.setProperty('--teal-700', p.t700);
  r.setProperty('--teal-500', p.t500);
  r.setProperty('--teal-300', p.t300);
  r.setProperty('--gold', p.gold);
  r.setProperty('--gold-deep', p.goldDeep);
  r.setProperty('--gold-pale', p.goldPale);
  r.setProperty('--cloud', p.cloud);
  r.setProperty('--cloud-2', p.cloud2);
  r.setProperty('--txt', p.txt);
  r.setProperty('--txt-2', p.txt2);
  r.setProperty('--txt-3', p.txt3);
  r.setProperty('--line', 'rgba(' + p.line + ',.13)');
  r.setProperty('--line-soft', 'rgba(' + p.line + ',.07)');
  r.setProperty('--line-strong', 'rgba(' + p.line + ',.24)');
}
applyPalette(TWEAK_DEFAULTS.palette || '绿松石');

const IS_EMBED = new URLSearchParams(location.search).get('embed') === 'mobile';

function App() {
  const [route, setRoute] = React.useState('home');
  const [param, setParam] = React.useState(null);
  const [shell, setShell] = React.useState(() => new URLSearchParams(location.search).get('admin') === '1' ? 'admin' : 'site'); // site | admin | arch
  const [device, setDeviceRaw] = React.useState(() => IS_EMBED ? 'desktop' : (localStorage.getItem('qhht-device') || 'desktop'));
  const setDevice = (v) => { if (!IS_EMBED) setDeviceRaw(v); };
  React.useEffect(() => { if (!IS_EMBED) localStorage.setItem('qhht-device', device); }, [device]);

  React.useEffect(() => {
    try {
      const s = JSON.parse(localStorage.getItem('qhht-nav') || '{}');
      if (s.route) setRoute(s.route);
      if (s.param) setParam(s.param);
      if (s.shell && new URLSearchParams(location.search).get('admin') !== '1') setShell(s.shell);
    } catch (e) { }
  }, []);

  const go = React.useCallback((r, p) => {
    setShell('site');
    setRoute(r);
    setParam(p || null);
    localStorage.setItem('qhht-nav', JSON.stringify({ route: r, param: p || null, shell: 'site' }));
    window.scrollTo({ top: 0, behavior: 'instant' in document.documentElement.style ? 'instant' : 'auto' });
  }, []);

  React.useEffect(() => { window.__go = go; window.__route = route; }, [go, route]);

  const setShellPersist = (s) => {
    setShell(s);
    localStorage.setItem('qhht-nav', JSON.stringify({ route, param, shell: s }));
  };

  useReveal();

  const PAGE = {
    home: <Home4 />, learn: <Learn />, dolores: <DoloresReal />, courses: <CoursesEventsPage key="ce" />,
    posts: <PostsPage />, library: <LibraryPage />, voices: <VoicesPage />, about: <About />,
    faq: <Faq />, book: <BookForm />, events: <CoursesEventsPage key="ev" />, backend: <BackendPage />,
    gallery: <GalleryTimeline id={param} key={'g' + param} />,
  };

  return (
    <AuthProvider>
      <div style={{ display: 'contents' }} key={'dir' + shell}>
        {/* 形态切换：右下角，避开正文 */}
        <div style={{
          display: IS_EMBED ? 'none' : 'flex',
          position: 'fixed', bottom: 18, right: 18, zIndex: 800,
          flexDirection: 'column', gap: 2, padding: 4, borderRadius: 12,
          background: 'rgba(11,36,38,.86)', backdropFilter: 'blur(20px) saturate(160%)',
          boxShadow: '0 14px 44px -12px rgba(0,0,0,.45)', border: '1px solid rgba(238,244,243,.12)'
        }}>
          <div style={{ fontFamily: 'var(--f-mono)', fontSize: 8, letterSpacing: '.16em', color: 'rgba(238,244,243,.38)', textAlign: 'center', padding: '3px 0 5px', textTransform: 'uppercase' }}>原型</div>
          {[['site', '新官网'], ['admin', '运营后台'], ['arch', '架构方案'], ['backend', '后端手册']].map(([k, t]) => (
            <button key={k} onClick={() => setShellPersist(k)}
              style={{
                border: 0, borderRadius: 7, padding: '6px 13px', fontSize: 11.5,
                background: shell === k ? '#fff' : 'transparent',
                color: shell === k ? 'var(--ink)' : 'rgba(238,244,243,.7)',
                transition: 'all .3s', whiteSpace: 'nowrap', textAlign: 'left'
              }}>{t}</button>
          ))}
          <div style={{ height: 1, background: 'rgba(238,244,243,.12)', margin: '4px 6px' }} />
          {[['desktop', '电脑'], ['mobile', '手机']].map(([k, t]) => (
            <button key={k} onClick={() => setDevice(k)}
              style={{
                border: 0, borderRadius: 7, padding: '6px 13px', fontSize: 11.5,
                background: device === k ? 'var(--gold)' : 'transparent',
                color: device === k ? '#25190a' : 'rgba(238,244,243,.7)',
                transition: 'all .3s', whiteSpace: 'nowrap', textAlign: 'left'
              }}>{k === 'desktop' ? '▭ ' : '▯ '}{t}</button>
          ))}
        </div>

        {device === 'mobile' && <MobilePreview />}

        {shell === 'admin' ? <Admin /> : shell === 'arch' ? <Arch /> :
          <div style={device === 'mobile' ? { display: 'none' } : null}><Shell dir="B" route={route === 'events' || route === 'gallery' ? 'courses' : route}>
            {route === 'post' ? <PostDetail6 id={param} key={param} /> : (PAGE[route] || <Home />)}
          </Shell></div>
        }

        {!IS_EMBED && <TweakLayer device={device} setDevice={setDevice} />}
      </div>
    </AuthProvider>
  );
}

/* ---------- Tweaks ---------- */
function TweakLayer({ device, setDevice }) {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);

  React.useEffect(() => {
    const root = document.getElementById('root');
    if (root) root.setAttribute('data-dir', t.direction);
    document.body.setAttribute('data-dir', t.direction);
    document.body.setAttribute('data-grain', t.grain ? '1' : '0');
  }, [t.direction, t.grain]);

  React.useEffect(() => { applyPalette(t.palette); }, [t.palette]);

  const sw = Object.entries(PALETTES).map(([k, p]) => [p.t900, p.t500, p.gold, p.cloud]);
  const names = Object.keys(PALETTES);
  const cur = PALETTES[t.palette] || PALETTES['墨青'];

  return (
    <TweaksPanel>
      <TweakSection label="预览设备" />
      <TweakRadio label="屏幕" value={device}
        options={['desktop', 'mobile']}
        onChange={(v) => setDevice(v)} />

      <TweakSection label="调色方案" />
      <TweakColor label={'方案 · ' + t.palette}
        value={[cur.t900, cur.t500, cur.gold, cur.cloud]}
        options={sw}
        onChange={(v) => { const i = sw.findIndex((s) => s[0] === v[0]); setTweak('palette', names[i] || '墨青'); }} />
      <div style={{ fontSize: 10.5, color: 'rgba(41,38,27,.5)', lineHeight: 1.5, marginTop: -2 }}>
        绿松石（默认）· 墨青 · 暮紫 · 暖砂。整套主色、强调色、底色同时切换。
      </div>

      <TweakSection label="视觉方向" />
      <TweakRadio label="方向" value={t.direction} options={['A', 'B', 'C']}
        onChange={(v) => setTweak('direction', v)} />

      <TweakSection label="细节" />
      <TweakToggle label="颗粒质感" value={t.grain} onChange={(v) => setTweak('grain', v)} />
    </TweaksPanel>
  );
}

/* 手机预览：在 iframe 里以 390px 宽真实渲染同一份页面（媒体查询会真正生效） */
function MobilePreview() {
  const u = new URL(location.href);
  u.searchParams.set('embed', 'mobile');
  const src = u.toString();
  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 700, background: 'radial-gradient(circle at 50% 30%,#1a3a3d,#071a1c)', display: 'grid', placeItems: 'center', overflow: 'auto', padding: '28px 0' }}>
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 14 }}>
        <div style={{ fontFamily: 'var(--f-mono)', fontSize: 10, letterSpacing: '.18em', color: 'rgba(238,244,243,.5)', textTransform: 'uppercase' }}>手机预览 · 390 × 844</div>
        <div style={{ width: 410, height: 864, borderRadius: 54, background: '#0b0b0c', padding: 10, boxShadow: '0 40px 90px -20px rgba(0,0,0,.7), inset 0 0 0 2px #2a2a2c', position: 'relative' }}>
          <div style={{ position: 'absolute', top: 20, left: '50%', transform: 'translateX(-50%)', width: 112, height: 30, borderRadius: 20, background: '#000', zIndex: 2 }} />
          <iframe title="手机预览" src={src} style={{ width: 390, height: 844, border: 0, borderRadius: 44, background: '#fff', display: 'block' }} />
        </div>
      </div>
    </div>
  );
}

/* 先取数（快照 → 接口），再渲染。取数失败也照常渲染（用本地/快照）。 */
(async function boot() {
  if (typeof window.__bootData === 'function') {
    try { await window.__bootData(); } catch (e) { console.warn('[boot] 取数失败，使用内置数据', e); }
  }
  ReactDOM.createRoot(document.getElementById('root')).render(<App />);
})();
