// app.jsx — shell: theme application, in-phone header + tab bar, routing, caption, mount.

const TABS = [
  { k: 'trip', label: '트립', icon: 'trip' },
  { k: 'map', label: '지도', icon: 'map' },
  { k: 'album', label: '앨범', icon: 'album' },
  { k: 'wallet', label: '지갑', icon: 'wallet' },
  { k: 'home', label: '집', icon: 'home' },
];

const GRAIN = "url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E\")";

function AppHeader({ st, canBack, onBack }) {
  const stateObj = JJ_STATES.find(s => s.key === st.tripState);
  const pColor = st.persona === 'host' ? 'var(--host)' : 'var(--guest)';
  return (
    <div style={{ padding: '54px 18px 12px', flexShrink: 0, position: 'relative', zIndex: 6, borderBottom: '1px solid var(--line-soft)', background: 'var(--paper)' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <div style={{ width: 34, height: 34, flexShrink: 0, display: 'flex' }}>
        {canBack && (
          <button onClick={onBack} aria-label="뒤로" style={{
            width: 34, height: 34, borderRadius: '50%', flexShrink: 0, cursor: 'pointer',
            background: 'var(--card)', border: '1px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'center',
            boxShadow: '0 1px 3px var(--shadow)', WebkitTapHighlightColor: 'transparent',
          }}>
            <JJIcon name="chevL" size={18} color="var(--ink-2)" sw={2.2} />
          </button>
        )}
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontFamily: 'var(--f-display)', fontWeight: 700, fontSize: 19, color: 'var(--ink)', letterSpacing: '.03em', lineHeight: 1 }}>쩨우스</div>
          <div style={{ fontFamily: 'var(--f-body)', fontSize: 10.5, color: 'var(--ink-3)', marginTop: 3 }}>{JJ.home.place} · {JJ.trip.dates}</div>
        </div>
        <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6, background: `color-mix(in srgb, ${pColor} 12%, var(--card))`, border: `1px solid color-mix(in srgb, ${pColor} 28%, transparent)`, borderRadius: 999, padding: '4px 10px 4px 5px' }}>
          <Avatar name={st.persona === 'host' ? JJ.host.initial : JJ.guest.initial} tone={st.persona} size={24} />
          <span style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, fontWeight: 600, color: pColor }}>{st.persona === 'host' ? '호스트' : '손님'}</span>
        </div>
        <div style={{ display: 'inline-flex', alignItems: 'center', gap: 5, background: 'var(--card)', border: '1px solid var(--line)', borderRadius: 999, padding: '5px 11px' }}>
          <span style={{ width: 7, height: 7, borderRadius: '50%', background: `var(--${stateObj.tone})` }} />
          <span style={{ fontFamily: 'var(--f-body)', fontSize: 11.5, fontWeight: 600, color: 'var(--ink-2)' }}>{stateObj.name}</span>
        </div>
      </div>
    </div>
  );
}

function TabBar({ tab, onTab }) {
  return (
    <div style={{ flexShrink: 0, display: 'flex', padding: '8px 6px 26px', background: 'var(--paper)', borderTop: '1px solid var(--line-soft)', position: 'relative', zIndex: 6 }}>
      {TABS.map(t => {
        const on = tab === t.k;
        return (
          <button key={t.k} onClick={() => onTab(t.k)} style={{
            flex: 1, background: 'none', border: 'none', cursor: 'pointer', padding: '4px 0',
            display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4,
            WebkitTapHighlightColor: 'transparent',
          }}>
            <JJIcon name={t.icon} size={23} color={on ? 'var(--coral)' : 'var(--ink-3)'} sw={on ? 2 : 1.7} fill={on} />
            <span style={{ fontFamily: 'var(--f-body)', fontSize: 10.5, fontWeight: on ? 700 : 500, color: on ? 'var(--coral)' : 'var(--ink-3)' }}>{t.label}</span>
          </button>
        );
      })}
    </div>
  );
}

function PhoneApp({ st, set }) {
  const pushNav = (patch) => set({ ...patch, sheet: null, hist: [...(st.hist || []), { tab: st.tab, sub: st.sub }] });
  const go = (tab, sub = null) => pushNav({ tab, sub });
  const openSheet = (which) => set({ sheet: which });
  const setSub = (sub) => pushNav({ sub });
  const onTab = (k) => set({ tab: k, sub: null, sheet: null, hist: [] }); // 탭 = 루트 이동
  const back = () => {
    const h = st.hist || [];
    if (!h.length) return;
    const last = h[h.length - 1];
    set({ tab: last.tab, sub: last.sub, sheet: null, hist: h.slice(0, -1) });
  };
  const scr = resolveScr(st);

  let body;
  if (st.tab === 'trip') body = <TripTab persona={st.persona} tripState={st.tripState} scr={scr} go={go} openSheet={openSheet} />;
  else if (st.tab === 'map') body = <MapTab persona={st.persona} openSheet={openSheet} />;
  else if (st.tab === 'album') body = <AlbumTab persona={st.persona} scr={scr} />;
  else if (st.tab === 'wallet') body = <WalletTab persona={st.persona} tripState={st.tripState} scr={scr} />;
  else body = <HomeTab persona={st.persona} sub={st.sub} setSub={setSub} scr={scr} openSheet={openSheet} />;

  return (
    <div style={{ height: '100%', display: 'flex', flexDirection: 'column', background: 'var(--paper)', position: 'relative', color: 'var(--ink)' }}>
      {/* grain */}
      <div style={{ position: 'absolute', inset: 0, zIndex: 1, pointerEvents: 'none', opacity: 0.045, mixBlendMode: 'multiply', backgroundImage: GRAIN }} />
      <AppHeader st={st} canBack={(st.hist || []).length > 0} onBack={back} />
      <div key={st.tab + st.persona + st.tripState + (st.sub || '') + scr} style={{ flex: 1, overflowY: 'auto', overflowX: 'hidden', padding: '16px 18px 22px', position: 'relative', zIndex: 2, animation: 'jjFade .3s ease' }}>
        {body}
      </div>
      <TabBar tab={st.tab} onTab={onTab} />
      {st.sheet && <SheetHost which={st.sheet} onClose={() => set({ sheet: null })} />}
    </div>
  );
}

function Caption({ st }) {
  let active = null;
  for (const g of JJ_CATALOG) for (const e of g.items) if (matchActive(e, st)) { active = e; break; }
  const tabName = (TABS.find(t => t.k === st.tab) || {}).label;
  return (
    <div style={{ width: 312, maxWidth: '100%', marginTop: 18 }}>
      <div style={{ background: '#FFFDF7', border: '1px solid #E6D9BE', borderRadius: 16, padding: '15px 17px', boxShadow: '0 6px 22px rgba(86,61,32,.1)' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 7 }}>
          <span style={{ fontFamily: "'IBM Plex Sans KR',sans-serif", fontSize: 9.5, fontWeight: 700, letterSpacing: '.16em', textTransform: 'uppercase', color: '#A38B63' }}>지금 보는 화면</span>
          {active && <span style={{ fontFamily: "'Gowun Batang',serif", fontWeight: 700, fontSize: 11, background: '#DE7355', color: '#fff', borderRadius: 6, padding: '2px 7px' }}>기능 {active.feat}</span>}
          <span style={{ flex: 1 }} />
          <span style={{ fontSize: 10, fontWeight: 700, padding: '3px 8px', borderRadius: 6, background: st.persona === 'host' ? 'rgba(32,89,107,.12)' : 'rgba(222,115,85,.14)', color: st.persona === 'host' ? '#20596B' : '#DE7355' }}>{st.persona === 'host' ? '호스트 시점' : '손님 시점'}</span>
        </div>
        <div style={{ fontFamily: "'Gowun Batang',serif", fontWeight: 700, fontSize: 16, color: '#15323C' }}>{active ? active.name : `${tabName} 화면`}</div>
        <div style={{ fontFamily: "'IBM Plex Sans KR',sans-serif", fontSize: 12.5, color: '#3D5B66', marginTop: 3, lineHeight: 1.5 }}>{active ? active.spec : '하단 탭으로 자유롭게 둘러보거나, 왼쪽에서 화면을 골라보세요.'}</div>
      </div>
    </div>
  );
}

function DemoApp() {
  const [st, setSt] = React.useState({ persona: 'guest', tripState: 'invited', tab: 'trip', sub: null, sheet: null, scr: null, hist: [] });
  const [themeKey, setThemeKey] = React.useState('sunset');
  const [fontKey, setFontKey] = React.useState('classic');
  const [scale, setScale] = React.useState(1);
  const set = (patch) => setSt(s => ({ ...s, ...patch }));
  const directorSet = (patch) => setSt(s => ({ ...s, ...patch, hist: [] })); // 디렉터 점프 = 히스토리 리셋
  const vars = jjThemeVars(themeKey, fontKey);

  React.useEffect(() => {
    const fit = () => setScale(Math.min(1, Math.max(0.58, (window.innerHeight - 150) / 874)));
    fit();
    window.addEventListener('resize', fit);
    return () => window.removeEventListener('resize', fit);
  }, []);

  // 화면(컨텍스트)이 바뀌면 화면-상태를 해당 기본값으로 보정
  React.useEffect(() => {
    setSt(s => { const r = resolveScr(s); return s.scr === r ? s : { ...s, scr: r }; });
  }, [st.persona, st.tripState, st.tab, st.sub]);

  return (
    <div style={{ display: 'flex', minHeight: '100vh', width: '100%', alignItems: 'stretch' }}>
      <Director st={st} set={directorSet} scr={resolveScr(st)} setScr={(k) => set({ scr: k })} themeKey={themeKey} setTheme={setThemeKey} fontKey={fontKey} setFont={setFontKey} />
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'flex-start', padding: '32px 24px 48px', overflowY: 'auto', maxHeight: '100vh' }}>
        <div style={{ height: 874 * scale, flexShrink: 0 }}>
          <div style={{ transform: `scale(${scale})`, transformOrigin: 'top center' }}>
            <div style={{ ...vars }}>
              <IOSDevice>
                <PhoneApp st={st} set={set} />
              </IOSDevice>
            </div>
          </div>
        </div>
        <Caption st={st} />
      </div>
    </div>
  );
}

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