/* ============================================================
   F2 UI — Storybook shell (layout · sidebar · topbar · doc page)
   Reads window.F2Stories + window.SB.* and renders the explorer.
   ============================================================ */
(function () {
  const F2 = window.F2;
  const SB = window.SB;
  const { Icon, Badge } = F2;
  const { Canvas, Controls, CodePanel, PropsTable, VariantGallery, A11yPanel, Block, Mono, Segmented, useStored } = SB;

  const GROUP_ORDER = ['Overview', 'Core', 'Forms', 'Navigation', 'Data display', 'Feedback', 'Dashboard', 'Marketing', 'Diagram'];
  const GROUP_ICON = {
    Overview: 'BookOpen', Core: 'Square', Forms: 'TextCursorInput', Navigation: 'Compass',
    'Data display': 'LayoutList', Feedback: 'MessageSquareWarning', Dashboard: 'LayoutDashboard',
    Marketing: 'Megaphone', Diagram: 'Workflow',
  };

  function groupStories(stories) {
    const map = {};
    stories.forEach((s) => { (map[s.group] = map[s.group] || []).push(s); });
    const order = [...GROUP_ORDER, ...Object.keys(map).filter((g) => !GROUP_ORDER.includes(g))];
    return order.filter((g) => map[g]).map((g) => ({ group: g, items: map[g] }));
  }

  function defaultsFor(story) {
    const d = {};
    (story.props || []).forEach((p) => { if ('default' in p) d[p.name] = p.default; });
    return d;
  }

  /* ---------------- brand mark ---------------- */
  function BrandMark() {
    const cell = (amber) => ({ width: 9, height: 9, borderRadius: 2.5, background: amber ? 'var(--f2-accent)' : 'var(--f2-surface-card)', border: amber ? 'none' : '1px solid var(--f2-border-strong)' });
    return (
      <div style={{ display: 'flex', alignItems: 'center', gap: 11 }}>
        <div style={{ display: 'grid', gridTemplateColumns: '9px 9px', gap: 3 }}>
          <span style={cell()} /><span style={cell()} /><span style={cell()} /><span style={cell(true)} />
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', lineHeight: 1 }}>
          <span style={{ fontFamily: 'var(--f2-font-display)', fontWeight: 700, fontSize: 17, letterSpacing: '-0.02em', color: 'var(--f2-text)' }}>F2 <span style={{ color: 'var(--f2-text-muted)', fontWeight: 500 }}>UI</span></span>
          <span style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 9, letterSpacing: '0.18em', color: 'var(--f2-text-faint)', marginTop: 4 }}>COMPONENT LIBRARY</span>
        </div>
      </div>
    );
  }

  /* ---------------- sidebar ---------------- */
  function Sidebar({ groups, currentId, onSelect, query, setQuery, total, searchRef }) {
    return (
      <aside style={{ display: 'flex', flexDirection: 'column', height: '100vh', borderRight: '1px solid var(--f2-border)', background: 'var(--f2-surface)' }}>
        <div style={{ padding: '20px 20px 16px' }}>
          <BrandMark />
        </div>
        <div style={{ padding: '0 16px 14px' }}>
          <div style={{ position: 'relative', display: 'flex', alignItems: 'center' }}>
            <span style={{ position: 'absolute', left: 12, color: 'var(--f2-text-faint)', pointerEvents: 'none' }}><Icon name="Search" size={15} /></span>
            <input ref={searchRef} value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Search components"
              style={{
                width: '100%', height: 38, padding: '0 34px 0 34px', background: 'var(--f2-surface-raised)',
                border: '1px solid var(--f2-border)', borderRadius: 'var(--f2-radius-control)', color: 'var(--f2-text)',
                fontFamily: 'var(--f2-font-body)', fontSize: 14, outline: 'none',
              }} />
            {query
              ? <button onClick={() => setQuery('')} aria-label="Clear" style={{ position: 'absolute', right: 8, background: 'none', border: 'none', color: 'var(--f2-text-faint)', cursor: 'pointer', display: 'inline-flex' }}><Icon name="X" size={14} /></button>
              : <kbd style={{ position: 'absolute', right: 10, fontFamily: 'var(--f2-font-mono)', fontSize: 11, color: 'var(--f2-text-faint)', border: '1px solid var(--f2-border)', borderRadius: 5, padding: '2px 6px', background: 'var(--f2-surface-sunken)' }}>/</kbd>}
          </div>
        </div>
        <nav style={{ flex: 1, overflowY: 'auto', padding: '0 10px 24px' }}>
          {groups.length === 0 && <div style={{ padding: '12px 12px', color: 'var(--f2-text-faint)', fontSize: 13.5 }}>No matches.</div>}
          {groups.map(({ group, items }) => (
            <div key={group} style={{ marginBottom: 6 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '14px 10px 7px' }}>
                <Icon name={GROUP_ICON[group] || 'Square'} size={13} color="var(--f2-text-faint)" />
                <Mono style={{ fontSize: 10.5, color: 'var(--f2-text-faint)' }}>{group}</Mono>
                <Mono style={{ fontSize: 10.5, color: 'var(--f2-text-faint)', opacity: 0.6 }}>{items.length}</Mono>
              </div>
              {items.map((s) => {
                const on = s.id === currentId;
                return (
                  <button key={s.id} onClick={() => onSelect(s.id)} style={{
                    display: 'flex', alignItems: 'center', gap: 9, width: '100%', textAlign: 'left',
                    padding: '7px 10px', marginBottom: 1, border: 'none', cursor: 'pointer', borderRadius: 8,
                    background: on ? 'var(--f2-surface-card)' : 'transparent',
                    boxShadow: on ? 'inset 0 0 0 1px var(--f2-border)' : 'none',
                    color: on ? 'var(--f2-text)' : 'var(--f2-text-secondary)',
                    fontFamily: 'var(--f2-font-body)', fontSize: 14, transition: 'background var(--f2-dur-fast) var(--f2-ease)',
                  }}
                    onMouseEnter={(e) => { if (!on) e.currentTarget.style.background = 'var(--f2-surface-raised)'; }}
                    onMouseLeave={(e) => { if (!on) e.currentTarget.style.background = 'transparent'; }}>
                    <span style={{ width: 5, height: 5, borderRadius: 2, flex: '0 0 auto', background: on ? 'var(--f2-accent)' : 'var(--f2-border-strong)' }} />
                    <span style={{ flex: 1 }}>{s.name}</span>
                    {s.status === 'new' && <span style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 9, letterSpacing: '0.1em', color: 'var(--f2-accent-text)', border: '1px solid var(--f2-accent-border)', borderRadius: 4, padding: '1px 5px' }}>NEW</span>}
                  </button>
                );
              })}
            </div>
          ))}
        </nav>
        <div style={{ padding: '12px 20px', borderTop: '1px solid var(--f2-border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <Mono style={{ fontSize: 10 }}>{total} components</Mono>
          <Mono style={{ fontSize: 10, color: 'var(--f2-text-faint)' }}>v1.0</Mono>
        </div>
      </aside>
    );
  }

  /* ---------------- topbar ---------------- */
  function Topbar({ story, theme, setTheme, width, setWidth }) {
    return (
      <header style={{
        display: 'flex', alignItems: 'center', gap: 16, padding: '0 28px', height: 60, flex: '0 0 auto',
        borderBottom: '1px solid var(--f2-border)', background: 'var(--f2-surface)',
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 9, minWidth: 0 }}>
          <Mono style={{ color: 'var(--f2-text-faint)' }}>{story.group}</Mono>
          <Icon name="ChevronRight" size={13} color="var(--f2-text-faint)" />
          <span style={{ fontFamily: 'var(--f2-font-display)', fontWeight: 600, fontSize: 15, color: 'var(--f2-text)', whiteSpace: 'nowrap' }}>{story.name}</span>
          {story.status === 'new' && <Badge tone="active" style={{ marginLeft: 2 }}>New</Badge>}
        </div>
        <div style={{ flex: 1 }} />
        {!story.page && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <Segmented size="sm" aria-label="Viewport width" value={width} onChange={setWidth} options={[
              { value: 'xs', icon: 'Smartphone', title: 'Mobile · 390' },
              { value: 'sm', icon: 'Tablet', title: 'Tablet · 768' },
              { value: 'md', icon: 'Monitor', title: 'Desktop · 1024' },
              { value: 'full', icon: 'MoveHorizontal', title: 'Responsive' },
            ]} />
            <Segmented size="sm" aria-label="Preview theme" value={theme} onChange={setTheme} options={[
              { value: 'dark', icon: 'Moon', title: 'Dark' },
              { value: 'light', icon: 'Sun', title: 'Light' },
            ]} />
          </div>
        )}
      </header>
    );
  }

  /* ---------------- doc page ---------------- */
  function ImportLine({ text }) {
    const [copied, setCopied] = React.useState(false);
    return (
      <button onClick={() => SB.copy(text, (ok) => { setCopied(ok); setTimeout(() => setCopied(false), 1300); })}
        title="Copy import" style={{
          display: 'inline-flex', alignItems: 'center', gap: 10, padding: '7px 12px', cursor: 'pointer',
          background: 'var(--f2-surface-sunken)', border: '1px solid var(--f2-border)', borderRadius: 'var(--f2-radius-control)',
          fontFamily: 'var(--f2-font-mono)', fontSize: 12.5, color: 'var(--f2-text-secondary)',
        }}>
        <span dangerouslySetInnerHTML={{ __html: SB.highlight(text) }} />
        <Icon name={copied ? 'Check' : 'Copy'} size={13} color={copied ? 'var(--f2-accent-text)' : 'var(--f2-text-faint)'} />
      </button>
    );
  }

  function DocPage({ story, theme, setTheme, width, setWidth }) {
    const [values, setValues] = React.useState(() => defaultsFor(story));
    React.useEffect(() => { setValues(defaultsFor(story)); }, [story.id]);

    if (story.page) {
      return (
        <main style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0 }}>
          <Topbar story={story} theme={theme} setTheme={setTheme} width={width} setWidth={setWidth} />
          <div style={{ flex: 1, overflowY: 'auto' }}>{story.render(values, F2)}</div>
        </main>
      );
    }

    const code = (() => {
      try { return story.code ? story.code(values, F2) : `<${story.name} />`; }
      catch (e) { return `<${story.name} />`; }
    })();

    return (
      <main style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0 }}>
        <Topbar story={story} theme={theme} setTheme={setTheme} width={width} setWidth={setWidth} />
        <div style={{ flex: 1, overflowY: 'auto' }}>
          <div style={{ maxWidth: 980, margin: '0 auto', padding: '40px 28px 120px', display: 'flex', flexDirection: 'column', gap: 40 }}>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
              <div>
                <h1 style={{ margin: 0, fontFamily: 'var(--f2-font-display)', fontWeight: 700, fontSize: 36, letterSpacing: '-0.03em', color: 'var(--f2-text)' }}>{story.name}</h1>
                {story.tagline && <p style={{ margin: '12px 0 0', fontSize: 18, lineHeight: 1.55, color: 'var(--f2-text-secondary)', maxWidth: 680 }}>{story.tagline}</p>}
              </div>
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10, alignItems: 'center' }}>
                {story.importLine && <ImportLine text={story.importLine} />}
                {(story.keywords || []).map((k) => (
                  <span key={k} style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 11, color: 'var(--f2-text-faint)', border: '1px solid var(--f2-border)', borderRadius: 'var(--f2-radius-pill)', padding: '3px 10px' }}>{k}</span>
                ))}
              </div>
            </div>

            <Canvas story={story} values={values} theme={theme} width={width} />
            <Controls story={story} values={values} setValues={setValues} />
            <CodePanel code={code} />
            <VariantGallery examples={story.examples} theme={theme} />
            <PropsTable props={story.props} />
            <A11yPanel notes={story.a11y} />

            {story.notes && (
              <Block label="Notes">
                <div style={{ border: '1px solid var(--f2-border)', borderRadius: 'var(--f2-radius-md)', padding: '18px 20px', background: 'var(--f2-surface-card)', fontSize: 14.5, lineHeight: 1.6, color: 'var(--f2-text-secondary)' }} dangerouslySetInnerHTML={{ __html: story.notes }} />
              </Block>
            )}
          </div>
        </div>
      </main>
    );
  }

  /* ---------------- app root ---------------- */
  function App() {
    const stories = window.F2Stories;
    const [query, setQuery] = React.useState('');
    const [theme, setTheme] = useStored('f2sb.theme', 'dark');
    const [width, setWidth] = useStored('f2sb.width', 'full');
    const [currentId, setCurrentId] = useStored('f2sb.story', stories[0] && stories[0].id);
    const searchRef = React.useRef(null);

    // hash sync
    React.useEffect(() => {
      const fromHash = decodeURIComponent((location.hash || '').replace(/^#/, ''));
      if (fromHash && stories.some((s) => s.id === fromHash)) setCurrentId(fromHash);
      const onHash = () => {
        const h = decodeURIComponent((location.hash || '').replace(/^#/, ''));
        if (h && stories.some((s) => s.id === h)) setCurrentId(h);
      };
      window.addEventListener('hashchange', onHash);
      return () => window.removeEventListener('hashchange', onHash);
    }, []);

    const select = (id) => { setCurrentId(id); if (location.hash.replace(/^#/, '') !== id) location.hash = id; const main = document.querySelector('main > div'); if (main) main.scrollTop = 0; };

    // keyboard: "/" or cmd/ctrl-k focuses search
    React.useEffect(() => {
      const onKey = (e) => {
        if ((e.key === '/' || ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k')) && document.activeElement !== searchRef.current) {
          e.preventDefault(); searchRef.current && searchRef.current.focus();
        } else if (e.key === 'Escape' && document.activeElement === searchRef.current) {
          setQuery(''); searchRef.current.blur();
        }
      };
      window.addEventListener('keydown', onKey);
      return () => window.removeEventListener('keydown', onKey);
    }, []);

    const q = query.trim().toLowerCase();
    const filtered = !q ? stories : stories.filter((s) =>
      (s.name + ' ' + s.group + ' ' + (s.keywords || []).join(' ') + ' ' + (s.tagline || '')).toLowerCase().includes(q));
    const groups = groupStories(filtered);
    const current = stories.find((s) => s.id === currentId) || stories[0];

    return (
      <div style={{ display: 'grid', gridTemplateColumns: '288px 1fr', height: '100vh', overflow: 'hidden' }}>
        <Sidebar groups={groups} currentId={current && current.id} onSelect={select} query={query} setQuery={setQuery} total={stories.length} searchRef={searchRef} />
        {current
          ? <DocPage key={current.id} story={current} theme={theme} setTheme={setTheme} width={width} setWidth={setWidth} />
          : <main style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Mono>No stories loaded.</Mono></main>}
      </div>
    );
  }

  window.__F2_MOUNT__ = function () {
    if (!window.F2Stories || !window.F2Stories.length) {
      document.getElementById('root').innerHTML = '<div style="padding:40px;font-family:var(--f2-font-mono);color:var(--f2-error)">No stories registered.</div>';
      return;
    }
    ReactDOM.createRoot(document.getElementById('root')).render(<App />);
  };
})();
