/* Starboard · Navigation
   Breadcrumb, NavigationMenu, SidebarNav, PaginationV2.
   Requires: navigation.css, a11y.js, position.js, React 18.
   Load with: <script type="text/babel" src="Navigation.jsx"></script> */

/* ── Shared chevrons ── */
const AdBcSep = () => (
  <svg className="ad-bc__sep" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="m9 18 6-6-6-6"/></svg>
);
const AdNavChevDown = ({ className }) => (
  <svg className={className} width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg>
);
const AdNavHomeIcon = () => (
  <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="M3 11 12 3l9 8v10a1 1 0 0 1-1 1h-5v-7H9v7H4a1 1 0 0 1-1-1V11z"/></svg>
);

/* ════════════════════════════════════════════════════════════
   Breadcrumb — items=[{label, href?, icon?}], maxItems collapses
   the middle into an ellipsis menu. Optional leading home icon.
   ════════════════════════════════════════════════════════════ */
const Breadcrumb = ({ items = [], maxItems, home = false, homeHref = '#' }) => {
  const [moreOpen, setMoreOpen] = React.useState(false);
  const moreBtnRef = React.useRef(null);
  const menuRef = React.useRef(null);
  const wrapRef = React.useRef(null);
  const { style } = adUseAnchorPosition(moreBtnRef, menuRef, moreOpen, { placement: 'bottom-start', offset: 6 });
  adUseDismiss(wrapRef, moreOpen, () => setMoreOpen(false));

  const collapse = maxItems && items.length > maxItems;
  const head = collapse ? items.slice(0, 1) : [];
  const hiddenItems = collapse ? items.slice(1, items.length - (maxItems - 2)) : [];
  const tail = collapse ? items.slice(items.length - (maxItems - 2)) : items;

  const renderItem = (item, isLast) => (
    isLast ? (
      <span className="ad-bc__current" aria-current="page">{item.icon}{item.label}</span>
    ) : (
      <a className="ad-bc__link" href={item.href || '#'}>{item.icon}{item.label}</a>
    )
  );

  return (
    <nav className="ad-bc" aria-label="Breadcrumb">
      <ol className="ad-bc__list">
        {home && (
          <li className="ad-bc__item">
            <a className="ad-bc__link ad-bc__home" href={homeHref} aria-label="Home"><AdNavHomeIcon /></a>
            <AdBcSep />
          </li>
        )}
        {head.map((item, i) => (
          <li key={`h-${i}`} className="ad-bc__item">
            {renderItem(item, false)}
            <AdBcSep />
          </li>
        ))}
        {collapse && (
          <li className="ad-bc__item" ref={wrapRef}>
            <button
              ref={moreBtnRef}
              type="button"
              className="ad-bc__more"
              aria-label={`Show ${hiddenItems.length} hidden levels`}
              aria-haspopup="true"
              aria-expanded={moreOpen}
              onClick={() => setMoreOpen(!moreOpen)}
            >···</button>
            {moreOpen && (
              <div ref={menuRef} className="ad-bc__menu" style={style}>
                {hiddenItems.map((item, i) => (
                  <a key={i} className="ad-bc__menu-item" href={item.href || '#'} onClick={() => setMoreOpen(false)}>
                    {item.icon}{item.label}
                  </a>
                ))}
              </div>
            )}
            <AdBcSep />
          </li>
        )}
        {tail.map((item, i) => {
          const isLast = i === tail.length - 1;
          return (
            <li key={`t-${i}`} className="ad-bc__item">
              {renderItem(item, isLast)}
              {!isLast && <AdBcSep />}
            </li>
          );
        })}
      </ol>
    </nav>
  );
};

/* ════════════════════════════════════════════════════════════
   NavigationMenu — horizontal marketing nav. Items are links or
   mega-panel triggers; sliding underline indicator; open panel
   follows hover once any panel is open.
   items=[{label, href?} | {label, panel:[{icon,label,description,href}]}]
   ════════════════════════════════════════════════════════════ */
const NavigationMenu = ({ items = [], ariaLabel = 'Main' }) => {
  const [openIndex, setOpenIndex] = React.useState(null);
  const [indicator, setIndicator] = React.useState(null);
  const listRef = React.useRef(null);
  const itemRefs = React.useRef([]);
  const panelAnchorRef = React.useRef(null);
  const panelRef = React.useRef(null);
  const navRef = React.useRef(null);
  const { onKeyDown, itemProps, setIndex } = adUseRovingTabindex(items.length, { orientation: 'horizontal', loop: true });

  panelAnchorRef.current = openIndex !== null ? itemRefs.current[openIndex] : null;
  const { style: panelStyle } = adUseAnchorPosition(panelAnchorRef, panelRef, openIndex !== null, { placement: 'bottom-start', offset: 8 });
  adUseDismiss(navRef, openIndex !== null, () => setOpenIndex(null));

  const moveIndicator = (i) => {
    const el = itemRefs.current[i];
    const list = listRef.current;
    if (!el || !list) return setIndicator(null);
    const a = el.getBoundingClientRect();
    const b = list.getBoundingClientRect();
    setIndicator({ left: a.left - b.left + 8, width: a.width - 16 });
  };

  const onItemEnter = (i) => {
    moveIndicator(i);
    if (openIndex !== null && items[i].panel) setOpenIndex(i); // hover-follow once open
  };

  const toggle = (i) => {
    if (items[i].panel) setOpenIndex(openIndex === i ? null : i);
  };

  return (
    <nav ref={navRef} className="ad-nm" role="navigation" aria-label={ariaLabel}>
      <ul ref={listRef} className="ad-nm__list" onKeyDown={(e) => {
        if (e.key === 'Escape') { setOpenIndex(null); return; }
        onKeyDown(e);
        if (['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(e.key)) {
          requestAnimationFrame(() => {
            const focused = itemRefs.current.findIndex((el) => el === document.activeElement);
            if (focused >= 0) {
              moveIndicator(focused);
              if (openIndex !== null && items[focused].panel) setOpenIndex(focused);
            }
          });
        }
      }} onMouseLeave={() => moveIndicator(openIndex !== null ? openIndex : -1)}>
        {items.map((item, i) => {
          const Tag = item.panel ? 'button' : 'a';
          return (
            <li key={i}>
              <Tag
                ref={(el) => { itemRefs.current[i] = el; }}
                className={`ad-nm__trigger${openIndex === i ? ' is-open' : ''}`}
                href={item.panel ? undefined : (item.href || '#')}
                type={item.panel ? 'button' : undefined}
                aria-haspopup={item.panel ? 'true' : undefined}
                aria-expanded={item.panel ? openIndex === i : undefined}
                {...itemProps(i)}
                onMouseEnter={() => onItemEnter(i)}
                onFocus={() => { setIndex(i); moveIndicator(i); }}
                onClick={() => toggle(i)}
                onKeyDown={(e) => { if (item.panel && (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ')) { e.preventDefault(); setOpenIndex(i); } }}
              >
                {item.label}
                {item.panel && <AdNavChevDown className="ad-nm__chev" />}
              </Tag>
            </li>
          );
        })}
        {indicator && <span className="ad-nm__indicator" style={indicator} aria-hidden="true" />}
      </ul>
      {openIndex !== null && items[openIndex].panel && (
        <div ref={panelRef} className="ad-nm__panel" style={panelStyle} role="group" aria-label={items[openIndex].label}>
          <div className="ad-nm__panel-grid">
            {items[openIndex].panel.map((p, i) => (
              <a key={i} className="ad-nm__panel-item" href={p.href || '#'}>
                {p.icon && <span className="ad-nm__panel-icon">{p.icon}</span>}
                <span>
                  <span className="ad-nm__panel-label">{p.label}</span>
                  {p.description && <span className="ad-nm__panel-desc" style={{ display: 'block' }}>{p.description}</span>}
                </span>
              </a>
            ))}
          </div>
        </div>
      )}
    </nav>
  );
};

/* ════════════════════════════════════════════════════════════
   SidebarNav — app-agnostic. Expanded (280px) / rail (72px).
   sections=[{label, items:[{key,label,icon,count?,children?:[{key,label,count?}]}]}]
   Keyboard: Up/Down roving over rows, Right/Left expand/collapse group.
   ════════════════════════════════════════════════════════════ */
const SidebarNav = ({
  sections = [],
  active,
  onSelect,
  collapsed,            // controlled rail state (optional)
  defaultCollapsed = false,
  onCollapsedChange,
  ariaLabel = 'Sidebar',
}) => {
  const [innerCollapsed, setInnerCollapsed] = React.useState(defaultCollapsed);
  const isRail = collapsed !== undefined ? collapsed : innerCollapsed;
  const setRail = (v) => { setInnerCollapsed(v); if (onCollapsedChange) onCollapsedChange(v); };
  const [openGroups, setOpenGroups] = React.useState(() => new Set(
    sections.flatMap((s) => s.items.filter((i) => i.children && i.defaultOpen).map((i) => i.key))
  ));
  const navRef = React.useRef(null);

  const toggleGroup = (key, force) => setOpenGroups((s) => {
    const n = new Set(s);
    const open = force !== undefined ? force : !n.has(key);
    open ? n.add(key) : n.delete(key);
    return n;
  });

  /* Keyboard: roving focus over visible rows */
  const onNavKeyDown = (e) => {
    const rows = Array.from(navRef.current.querySelectorAll('[data-sn-row]'))
      .filter((el) => el.offsetParent !== null);
    const i = rows.indexOf(document.activeElement);
    if (e.key === 'ArrowDown') { e.preventDefault(); (rows[i + 1] || rows[0]).focus(); }
    else if (e.key === 'ArrowUp') { e.preventDefault(); (rows[i - 1] || rows[rows.length - 1]).focus(); }
    else if (e.key === 'Home') { e.preventDefault(); rows[0] && rows[0].focus(); }
    else if (e.key === 'End') { e.preventDefault(); rows[rows.length - 1] && rows[rows.length - 1].focus(); }
    else if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') {
      const key = document.activeElement && document.activeElement.getAttribute('data-sn-group');
      if (key) { e.preventDefault(); toggleGroup(key, e.key === 'ArrowRight'); }
    }
  };

  const renderRow = (item, isChild) => {
    const isGroup = !!item.children;
    const isOpen = openGroups.has(item.key);
    const isActive = active === item.key;
    return (
      <React.Fragment key={item.key}>
        <button
          type="button"
          data-sn-row
          data-sn-group={isGroup ? item.key : undefined}
          className={`ad-sn__row${isActive ? ' is-active' : ''}`}
          aria-expanded={isGroup ? isOpen : undefined}
          aria-current={isActive ? 'page' : undefined}
          onClick={() => (isGroup ? toggleGroup(item.key) : onSelect && onSelect(item.key))}
        >
          {item.icon && <span className="ad-sn__row-icon">{item.icon}</span>}
          <span className="ad-sn__row-label">{item.label}</span>
          {item.count !== undefined && <span className="ad-sn__row-count">{item.count}</span>}
          {isGroup && (
            <span className="ad-sn__row-chev">
              <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="m9 18 6-6-6-6"/></svg>
            </span>
          )}
          {isRail && <span className="ad-sn__tip" role="presentation">{item.label}</span>}
        </button>
        {isGroup && (
          <div className={`ad-sn__group-body${isOpen ? ' is-open' : ''}`}>
            <div>
              <div className="ad-sn__group-children">
                {item.children.map((c) => renderRow(c, true))}
              </div>
            </div>
          </div>
        )}
      </React.Fragment>
    );
  };

  return (
    <nav ref={navRef} className={`ad-sn${isRail ? ' ad-sn--rail' : ''}`} aria-label={ariaLabel} onKeyDown={onNavKeyDown}>
      {sections.map((s, i) => (
        <div key={i} className="ad-sn__section">
          {s.label && <div className="ad-sn__section-label">{s.label}</div>}
          {s.items.map((item) => renderRow(item, false))}
        </div>
      ))}
      <button
        type="button"
        className="ad-sn__toggle"
        aria-label={isRail ? 'Expand sidebar' : 'Collapse sidebar'}
        aria-expanded={!isRail}
        onClick={() => setRail(!isRail)}
      >
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="m11 17-5-5 5-5M18 17l-5-5 5-5"/></svg>
        {!isRail && <span>Collapse</span>}
      </button>
    </nav>
  );
};

/* ════════════════════════════════════════════════════════════
   PaginationV2 — numbered (smart ellipsis), compact, load-more,
   optional jump-to-page. Last/first arrows fade to disabled.
   ════════════════════════════════════════════════════════════ */
const adPg2Window = (page, total) => {
  if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1);
  if (page <= 4) return [1, 2, 3, 4, 5, '…', total];
  if (page >= total - 3) return [1, '…', total - 4, total - 3, total - 2, total - 1, total];
  return [1, '…', page - 1, page, page + 1, '…', total];
};

const PaginationV2 = ({
  variant = 'numbered',        // 'numbered' | 'compact' | 'loadmore'
  page = 1,
  totalPages = 1,
  onPageChange,
  jump = false,
  // load-more
  loaded,
  total,
  batch = 25,
  onLoadMore,
  itemsLabel = 'loaded',
}) => {
  const [jumpVal, setJumpVal] = React.useState('');
  const [jumpInvalid, setJumpInvalid] = React.useState(false);
  const go = (p) => { if (p >= 1 && p <= totalPages && p !== page && onPageChange) onPageChange(p); };

  const commitJump = () => {
    const n = parseInt(jumpVal, 10);
    if (!n || n < 1 || n > totalPages) {
      setJumpInvalid(true);
      setTimeout(() => setJumpInvalid(false), 600);
      return;
    }
    go(n);
    setJumpVal('');
  };

  if (variant === 'loadmore') {
    const pct = total ? Math.min(100, Math.round((loaded / total) * 100)) : 0;
    const remaining = Math.max(0, (total || 0) - (loaded || 0));
    return (
      <div className="ad-pg2-more" role="navigation" aria-label="Pagination">
        <button type="button" className="ad-pg2-more__btn" disabled={remaining === 0} onClick={onLoadMore}>
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>
          Load {Math.min(batch, remaining) || batch} more
        </button>
        <div className="ad-pg2-more__count"><b>{Number(loaded).toLocaleString()}</b> of <b>{Number(total).toLocaleString()}</b> {itemsLabel}</div>
        <div className="ad-pg2-more__track" role="progressbar" aria-valuenow={loaded} aria-valuemin="0" aria-valuemax={total} aria-label="Loaded">
          <div className="ad-pg2-more__fill" style={{ width: `${pct}%` }} />
        </div>
      </div>
    );
  }

  const prevBtn = (
    <button type="button" className="ad-pg2__btn" disabled={page <= 1} aria-label="Previous page" onClick={() => go(page - 1)}>
      <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="m15 18-6-6 6-6"/></svg>
    </button>
  );
  const nextBtn = (
    <button type="button" className="ad-pg2__btn" disabled={page >= totalPages} aria-label="Next page" onClick={() => go(page + 1)}>
      <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="m9 18 6-6-6-6"/></svg>
    </button>
  );

  if (variant === 'compact') {
    return (
      <nav className="ad-pg2 ad-pg2--compact" aria-label="Pagination">
        {prevBtn}
        <span className="ad-pg2__fraction" aria-current="page"><b>{page}</b> / {totalPages}</span>
        {nextBtn}
      </nav>
    );
  }

  return (
    <nav className="ad-pg2" aria-label="Pagination">
      {prevBtn}
      {adPg2Window(page, totalPages).map((p, i) =>
        p === '…'
          ? <span key={`d-${i}`} className="ad-pg2__dots" aria-hidden="true">···</span>
          : (
            <button
              key={p}
              type="button"
              className="ad-pg2__btn"
              aria-current={p === page ? 'page' : undefined}
              aria-label={p === page ? `Page ${p}, current page` : `Go to page ${p}`}
              onClick={() => go(p)}
            >{p}</button>
          )
      )}
      {nextBtn}
      {jump && (
        <span className="ad-pg2__jump">
          Go to
          <input
            className={`ad-pg2__jump-input${jumpInvalid ? ' is-invalid' : ''}`}
            value={jumpVal}
            inputMode="numeric"
            aria-label={`Jump to page, 1 to ${totalPages}`}
            onChange={(e) => setJumpVal(e.target.value.replace(/[^0-9]/g, ''))}
            onKeyDown={(e) => { if (e.key === 'Enter') commitJump(); }}
          />
        </span>
      )}
    </nav>
  );
};

Object.assign(window, { Breadcrumb, NavigationMenu, SidebarNav, PaginationV2 });
