// js/_shared/SiteHeader.jsx
//
// Canonical site header. ONE component, every page.
// Ported from beava-design-system/project/ui_kits/_shared/SiteHeader.jsx
// with absolute paths so it works from any URL depth.
//
// Props:
//   active   — 'guide' | 'docs' | 'community' | null
//   search   — true to show ⌘K search bar in the middle (docs)
//   maxWidth — inner container width (1200 marketing, 1400 docs)
//
// Fallback index — used only when the Pagefind bundle fails to load
// (e.g. file:// or before `npm run build:search` has been run).
// The real index is generated by build-search.mjs into project/_pagefind/.
const SEARCH_INDEX_FALLBACK = [
  { title: 'Introduction',                      url: '/docs/',                                  section: 'Getting started' },
  { title: 'Install',                           url: '/docs/install/',                          section: 'Getting started' },
  { title: 'Quickstart',                        url: '/docs/get-started/quickstart/',           section: 'Getting started' },
  { title: 'Define a pipeline',                 url: '/docs/get-started/define-a-pipeline/',    section: 'Getting started' },
  { title: 'Push events',                       url: '/docs/get-started/push-events/',          section: 'Getting started' },
  { title: 'Query features',                    url: '/docs/get-started/query-features/',       section: 'Getting started' },
  { title: 'Streams',                           url: '/docs/concepts/streams/',                 section: 'Concepts' },
  { title: 'Tables',                            url: '/docs/concepts/tables/',                  section: 'Concepts' },
  { title: 'Windows',                           url: '/docs/concepts/windows/',                 section: 'Concepts' },
  { title: 'Operator catalog',                  url: '/docs/operators/',                        section: 'Reference' },
  { title: 'Python SDK',                        url: '/docs/sdk-api/python/',                   section: 'Reference' },
  { title: 'Why beava',                         url: '/docs/vision/why-beava/',                 section: 'Vision' },
  { title: 'Benchmarks',                        url: '/docs/vision/benchmarks/',                section: 'Vision' },
  { title: 'Non-goals and tradeoffs',           url: '/docs/vision/non-goals/',                 section: 'Vision' },
  { title: 'Guide',                             url: '/guide/',                                 section: 'Learn' },
  { title: 'Chapter 1: Per-customer dashboard', url: '/guide/chapter-1/',                       section: 'Learn' },
];

const SearchModal = ({ query, setQuery, onClose }) => {
  const [pagefind, setPagefind] = React.useState(null);
  const [pagefindFailed, setPagefindFailed] = React.useState(false);
  const [pagefindError, setPagefindError] = React.useState('');
  const [results, setResults] = React.useState([]);

  React.useEffect(() => {
    // Babel-standalone wraps `<script type="text/babel">` content in a way that
    // breaks native dynamic `import()` of pagefind.js. Bridge through a real
    // `<script type="module" src=...>` tag the browser parses natively.
    let mounted = true;

    const adopt = (mod) => {
      if (!mounted) return;
      if (mod && typeof mod.search === 'function') {
        if (mod.options) { try { mod.options({ excerptLength: 24 }); } catch (_) {} }
        setPagefind(mod);
      } else {
        const reason = 'Pagefind module loaded but has no search()';
        console.warn(reason, mod);
        setPagefindError(reason);
        setPagefindFailed(true);
      }
    };

    if (window.__pagefind) { adopt(window.__pagefind); return () => { mounted = false; }; }
    if (window.__pagefindError) { setPagefindError(window.__pagefindError); setPagefindFailed(true); return () => { mounted = false; }; }

    const onReady = () => adopt(window.__pagefind);
    const onFail = (e) => {
      const reason = (e && e.detail) || window.__pagefindError || 'unknown';
      console.warn('Pagefind bundle not available — using fallback index:', reason);
      if (mounted) { setPagefindError(String(reason)); setPagefindFailed(true); }
    };
    window.addEventListener('pagefind-ready', onReady);
    window.addEventListener('pagefind-failed', onFail);

    if (!document.getElementById('pagefind-loader')) {
      const script = document.createElement('script');
      script.id = 'pagefind-loader';
      script.type = 'module';
      script.src = '/_pagefind-loader.mjs';
      script.onerror = () => {
        const reason = 'failed to fetch /_pagefind-loader.mjs';
        window.__pagefindError = reason;
        window.dispatchEvent(new CustomEvent('pagefind-failed', { detail: reason }));
      };
      document.head.appendChild(script);
    }

    return () => {
      mounted = false;
      window.removeEventListener('pagefind-ready', onReady);
      window.removeEventListener('pagefind-failed', onFail);
    };
  }, []);

  React.useEffect(() => {
    const q = query.trim();
    if (pagefind) {
      if (!q) { setResults([]); return; }
      let cancelled = false;
      (async () => {
        try {
          const search = await pagefind.search(q);
          if (!search || !search.results) { if (!cancelled) setResults([]); return; }
          const data = await Promise.all(search.results.slice(0, 10).map(r => r.data()));
          if (!cancelled) setResults(data.map(d => ({
            url: d.url,
            title: (d.meta && d.meta.title) || d.url,
            section: (d.meta && d.meta.section) || '',
            excerpt: d.excerpt || '',
          })));
        } catch (e) {
          console.warn('Pagefind search failed', e);
          if (!cancelled) setResults([]);
        }
      })();
      return () => { cancelled = true; };
    }
    if (pagefindFailed) {
      const ql = q.toLowerCase();
      setResults(
        ql
          ? SEARCH_INDEX_FALLBACK.filter(p => (p.title + ' ' + p.section).toLowerCase().includes(ql))
          : SEARCH_INDEX_FALLBACK
      );
    }
  }, [query, pagefind, pagefindFailed]);

  const ready = pagefind || pagefindFailed;
  // Portal to <body> — the header sets `backdrop-filter: blur(...)`, which per
  // CSS spec turns it into the containing block for any descendant with
  // `position: fixed`, clipping the overlay to the header's 60px bounds.
  return ReactDOM.createPortal((
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, zIndex: 100,
      background: 'rgba(26,23,20,0.4)', backdropFilter: 'blur(4px)',
      display: 'flex', justifyContent: 'center', alignItems: 'flex-start',
      padding: '12vh 16px 16px',
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        background: '#fff', borderRadius: 14,
        border: '1px solid var(--border)',
        width: '100%', maxWidth: 560,
        boxShadow: '0 12px 40px rgba(26,23,20,0.18)',
        overflow: 'hidden',
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '14px 18px', borderBottom: '1px solid var(--border)' }}>
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--fg3)" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.35-4.35"/></svg>
          <input autoFocus value={query} onChange={e => setQuery(e.target.value)}
            placeholder="Search the docs..."
            onKeyDown={e => { if (e.key === 'Enter' && results[0]) { window.location.href = results[0].url; }}}
            style={{
              flex: 1, border: 'none', outline: 'none',
              fontFamily: 'var(--font-sans)', fontSize: 15, color: 'var(--fg1)',
              background: 'transparent',
            }}/>
          <span style={{
            fontFamily: 'var(--font-mono)', fontSize: 11,
            color: 'var(--fg3)', background: 'var(--beava-paper)',
            border: '1px solid var(--border)', borderRadius: 5,
            padding: '2px 7px', lineHeight: 1,
          }}>esc</span>
        </div>
        <div style={{ maxHeight: 360, overflowY: 'auto' }}>
          {!ready ? (
            <div style={{ padding: '32px 18px', textAlign: 'center', fontFamily: 'var(--font-sans)', fontSize: 14, color: 'var(--fg3)' }}>
              Loading search…
            </div>
          ) : !query.trim() ? (
            <div style={{ padding: '32px 18px', textAlign: 'center', fontFamily: 'var(--font-sans)', fontSize: 14, color: 'var(--fg3)' }}>
              Type to search the docs.
            </div>
          ) : results.length === 0 ? (
            <div style={{ padding: '32px 18px', textAlign: 'center', fontFamily: 'var(--font-sans)', fontSize: 14, color: 'var(--fg3)' }}>
              No matches for "<strong>{query}</strong>". Try a different term, or browse <a href="/docs/" style={{ color: 'var(--accent)', fontWeight: 600 }}>the docs index</a>.
            </div>
          ) : results.map(r => (
            <a key={r.url} href={r.url} style={{
              display: 'flex', flexDirection: 'column', gap: 4,
              padding: '12px 18px', borderBottom: '1px solid var(--border)',
              textDecoration: 'none', color: 'inherit',
            }}>
              <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 12 }}>
                <span style={{ fontFamily: 'var(--font-sans)', fontWeight: 600, fontSize: 14, color: 'var(--fg1)' }}>{r.title}</span>
                <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--fg3)' }}>{r.section}</span>
              </div>
              {r.excerpt && (
                <span
                  style={{ fontFamily: 'var(--font-sans)', fontSize: 13, color: 'var(--fg2)', lineHeight: 1.4 }}
                  dangerouslySetInnerHTML={{ __html: r.excerpt }}
                />
              )}
              <span style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--fg3)' }}>{r.url}</span>
            </a>
          ))}
        </div>
        <div style={{ padding: '10px 18px', fontFamily: 'var(--font-sans)', fontSize: 12, color: 'var(--fg3)', borderTop: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between' }}>
          <span><kbd style={{ fontFamily: 'var(--font-mono)', fontSize: 11, padding: '1px 5px', background: 'var(--beava-paper)', border: '1px solid var(--border)', borderRadius: 4 }}>↵</kbd> open first match</span>
          <span>
            {pagefindFailed && (
              <span style={{ marginRight: 8, color: 'var(--beava-warn)' }} title={pagefindError || 'pagefind module unavailable'}>
                fallback index{pagefindError ? `: ${pagefindError}` : ''}
              </span>
            )}
            {results.length} result{results.length === 1 ? '' : 's'}
          </span>
        </div>
      </div>
    </div>
  ), document.body);
};

const SiteHeader = ({ active = null, search = false, maxWidth = 1200 }) => {
  const [searchOpen, setSearchOpen] = React.useState(false);
  const [query, setQuery] = React.useState('');
  const [mobileMenuOpen, setMobileMenuOpen] = React.useState(false);
  React.useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') { e.preventDefault(); setSearchOpen(true); }
      if (e.key === 'Escape') { setSearchOpen(false); setMobileMenuOpen(false); }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);
  // Close mobile menu when viewport grows back over breakpoint
  React.useEffect(() => {
    const onResize = () => { if (window.innerWidth >= 760) setMobileMenuOpen(false); };
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);
  // Lock body scroll while mobile menu is open
  React.useEffect(() => {
    if (mobileMenuOpen) {
      const prev = document.body.style.overflow;
      document.body.style.overflow = 'hidden';
      return () => { document.body.style.overflow = prev; };
    }
  }, [mobileMenuOpen]);

  const inner = {
    maxWidth, width: '100%', margin: '0 auto',
    display: 'flex', alignItems: 'center', gap: 24,
  };

  const linkBase = {
    padding: '6px 10px', borderRadius: 7,
    fontSize: 14, fontWeight: 500,
    color: 'var(--fg2)', textDecoration: 'none',
    fontFamily: 'var(--font-sans)',
    display: 'inline-flex', alignItems: 'center', gap: 6,
    cursor: 'pointer',
  };
  const linkActive = { ...linkBase, color: 'var(--fg1)' };
  const dot = { width: 5, height: 5, borderRadius: 999, background: 'var(--accent)' };

  const Link = ({ id, label, href, external }) => {
    const isActive = active === id;
    return (
      <a href={href} className="bv-site-nav-link" style={isActive ? linkActive : linkBase}
         {...(external ? { target: '_blank', rel: 'noopener' } : {})}>
        {label}
        {isActive && <span style={dot}/>}
        {external && <span style={{ color: 'var(--fg3)', fontSize: 11 }}>↗</span>}
      </a>
    );
  };

  const HoverStyle = () => (
    <style>{`
      .bv-site-nav-link {
        position: relative;
      }
      .bv-site-nav-link::after {
        content: "";
        position: absolute;
        left: 10px;
        right: 10px;
        bottom: 2px;
        height: 1.5px;
        background: var(--accent);
        opacity: 0;
        transition: opacity 120ms;
      }
      .bv-site-nav-link:hover::after { opacity: 1; }
      .bv-site-nav-link:hover { color: var(--fg1) !important; }

      /* Hamburger button — hidden on desktop, shown on tablet+phone */
      .bv-hamburger { display: none; }

      /* Keep the search trigger label on a single line everywhere */
      .bv-search-trigger { white-space: nowrap; overflow: hidden; }
      .bv-search-trigger > span:first-of-type { overflow: hidden; text-overflow: ellipsis; }

      @media (max-width: 960px) {
        /* Inline desktop nav hides; hamburger appears at tablet width too */
        .bv-nav-desktop { display: none !important; }
        .bv-hamburger { display: inline-flex !important; }
      }

      @media (max-width: 760px) {
        /* Search shrinks to an icon-only button on phone */
        .bv-search-trigger { max-width: 40px !important; padding: 0 !important; justify-content: center !important; }
        .bv-search-trigger > span { display: none !important; }
      }

      /* Mobile menu drawer */
      .bv-mobile-menu-overlay {
        position: fixed; inset: 0; z-index: 80;
        background: rgba(26,23,20,0.5);
        backdrop-filter: blur(4px);
      }
      .bv-mobile-menu-panel {
        position: fixed; top: 60px; left: 0; right: 0; z-index: 81;
        background: var(--beava-paper);
        border-bottom: 1px solid var(--border);
        box-shadow: 0 12px 32px rgba(26,23,20,0.12);
        padding: 12px 18px 18px;
        max-height: calc(100vh - 60px);
        overflow-y: auto;
      }
      .bv-mobile-menu-link {
        display: flex !important; align-items: center; justify-content: space-between;
        padding: 14px 12px;
        font-family: var(--font-sans); font-size: 16px; font-weight: 500;
        color: var(--fg1) !important; text-decoration: none !important;
        border-bottom: 1px solid var(--border);
      }
      .bv-mobile-menu-link:last-child { border-bottom: 0; }
      .bv-mobile-menu-link.active { color: var(--accent) !important; }
      .bv-mobile-menu-link.active::after { display: none !important; }
      .bv-mobile-menu-link .ext { color: var(--fg3); font-size: 14px; }
    `}</style>
  );

  const MobileMenu = () => {
    if (!mobileMenuOpen) return null;
    const items = [
      { id: 'guide',     label: 'Guide',     href: '/guide/' },
      { id: 'docs',      label: 'Docs',      href: '/docs/' },
      { id: 'community', label: 'Community', href: '/community/' },
      { id: 'github',    label: 'GitHub',    href: 'https://github.com/beava-dev/beava', external: true },
      { id: 'discord',   label: 'Discord',   href: 'https://discord.gg/Jnx89PN9',        external: true },
    ];
    return ReactDOM.createPortal(
      <>
        <div className="bv-mobile-menu-overlay" onClick={() => setMobileMenuOpen(false)}/>
        <div className="bv-mobile-menu-panel">
          {items.map(it => (
            <a key={it.id} href={it.href}
               className={'bv-mobile-menu-link' + (active === it.id ? ' active' : '')}
               {...(it.external ? { target: '_blank', rel: 'noopener' } : {})}
               onClick={() => setMobileMenuOpen(false)}>
              <span>{it.label}</span>
              {it.external && <span className="ext">↗</span>}
            </a>
          ))}
        </div>
      </>,
      document.body
    );
  };

  const Hamburger = () => (
    <button className="bv-hamburger"
      onClick={() => setMobileMenuOpen(v => !v)}
      aria-label={mobileMenuOpen ? 'Close menu' : 'Open menu'}
      style={{
        alignItems: 'center', justifyContent: 'center',
        width: 40, height: 36, padding: 0,
        background: 'transparent', border: '1px solid var(--border)', borderRadius: 8,
        cursor: 'pointer', color: 'var(--fg1)',
      }}>
      {mobileMenuOpen ? (
        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
          <path d="M18 6L6 18M6 6l12 12"/>
        </svg>
      ) : (
        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
          <path d="M3 6h18M3 12h18M3 18h18"/>
        </svg>
      )}
    </button>
  );

  return (
    <header style={{
      position: 'sticky', top: 0, zIndex: 90,
      height: 60,
      background: 'rgba(253,250,244,0.96)',
      backdropFilter: 'blur(10px)',
      WebkitBackdropFilter: 'blur(10px)',
      borderBottom: '1px solid var(--border)',
      display: 'flex', alignItems: 'center',
      padding: '0 24px',
    }}>
      <HoverStyle/>
      <div style={inner}>
        <a href="/" style={{ display: 'inline-flex', alignItems: 'center', gap: 9, textDecoration: 'none', color: 'var(--fg1)' }}>
          <img src="/assets/logo-mark.png" alt="" width={30} height={30}/>
          <span style={{ fontFamily: 'var(--font-serif)', fontWeight: 700, fontSize: 22, letterSpacing: '-0.01em', lineHeight: 1 }}>beava</span>
          <span style={{
            fontFamily: 'var(--font-mono)', fontSize: 10.5, fontWeight: 600,
            color: 'var(--accent)', background: 'var(--beava-orange-wash)',
            padding: '2px 6px', borderRadius: 999, letterSpacing: '0.02em',
            marginLeft: 2,
          }}>v0</span>
        </a>

        {search ? (
          <div className="bv-search-trigger" style={{
            flex: 1, maxWidth: 360, margin: '0 auto',
            display: 'inline-flex', alignItems: 'center', gap: 8,
            height: 32, padding: '0 10px',
            background: '#fff',
            border: '1px solid var(--border)', borderRadius: 8,
            color: 'var(--fg3)', fontSize: 13, cursor: 'text',
            fontFamily: 'var(--font-sans)',
          }} tabIndex={0} role="button" aria-label="Search the docs"
             onClick={() => setSearchOpen(true)}>
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7"/><path d="M21 21l-4.35-4.35"/></svg>
            <span style={{ flex: 1 }}>Search the docs</span>
            <span style={{
              fontFamily: 'var(--font-mono)', fontSize: 11,
              color: 'var(--fg3)', background: 'var(--beava-paper)',
              border: '1px solid var(--border)', borderRadius: 5,
              padding: '1px 6px', lineHeight: 1,
            }}>⌘K</span>
          </div>
        ) : <div style={{ flex: 1 }}/>}

        <nav className="bv-nav-desktop" style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
          <Link id="guide" label="Guide" href="/guide/"/>
          <Link id="docs" label="Docs" href="/docs/"/>
          <Link id="community" label="Community" href="/community/"/>
          <Link id="github" label="GitHub" href="https://github.com/beava-dev/beava" external/>
          <Link id="discord" label="Discord" href="https://discord.gg/Jnx89PN9" external/>
        </nav>

        <Hamburger/>
      </div>
      <MobileMenu/>

      {searchOpen && <SearchModal query={query} setQuery={setQuery} onClose={() => setSearchOpen(false)}/>}
    </header>
  );
};
window.SiteHeader = SiteHeader;
