/* Starboard · Disclosure components
   Accordion, Collapsible, Tabs.
   Requires a11y.js. Load with:
     <script type="text/babel" src="Disclosure.jsx"></script> */

const AdDisclosureChevron = ({ className }) => (
  <svg className={className} 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>
);

/* ─── Accordion ───
   type="single" | "multiple", items = [{ value, trigger, content, meta? }]
   Up/Down move between triggers, Home/End jump. */
const Accordion = ({ type = 'single', items = [], defaultValue, variant = 'bordered', onValueChange, className = '' }) => {
  const [open, setOpen] = React.useState(() => {
    if (defaultValue == null) return [];
    return Array.isArray(defaultValue) ? defaultValue : [defaultValue];
  });
  const baseId = adUseId('acc');
  const triggerRefs = React.useRef([]);

  const toggle = (value) => {
    setOpen((prev) => {
      const has = prev.includes(value);
      const next = type === 'single'
        ? (has ? [] : [value])
        : (has ? prev.filter((v) => v !== value) : [...prev, value]);
      if (onValueChange) onValueChange(type === 'single' ? (next.length ? next[0] : null) : next);
      return next;
    });
  };

  const onTriggerKeyDown = (e, i) => {
    const n = items.length;
    let next = null;
    if (e.key === 'ArrowDown') next = (i + 1) % n;
    else if (e.key === 'ArrowUp') next = (i - 1 + n) % n;
    else if (e.key === 'Home') next = 0;
    else if (e.key === 'End') next = n - 1;
    if (next !== null) {
      e.preventDefault();
      const el = triggerRefs.current[next];
      if (el) el.focus();
    }
  };

  return (
    <div className={`ad-acc${variant === 'ghost' ? ' ad-acc--ghost' : ''} ${className}`}>
      {items.map((item, i) => {
        const isOpen = open.includes(item.value);
        const tid = `${baseId}-trigger-${i}`;
        const cid = `${baseId}-content-${i}`;
        return (
          <div key={item.value} className={`ad-acc__item${isOpen ? ' is-open' : ''}`}>
            <h3 className="ad-acc__heading">
              <button
                type="button"
                id={tid}
                ref={(el) => { triggerRefs.current[i] = el; }}
                className="ad-acc__trigger"
                aria-expanded={isOpen}
                aria-controls={cid}
                onClick={() => toggle(item.value)}
                onKeyDown={(e) => onTriggerKeyDown(e, i)}
              >
                <span className="ad-acc__label">{item.trigger}</span>
                {item.meta != null && <span className="ad-acc__meta">{item.meta}</span>}
                <AdDisclosureChevron className="ad-acc__chevron" />
              </button>
            </h3>
            <div id={cid} role="region" aria-labelledby={tid} className="ad-acc__content">
              <div className="ad-acc__inner">
                <div className="ad-acc__pad">{item.content}</div>
              </div>
            </div>
          </div>
        );
      })}
    </div>
  );
};

/* ─── Collapsible ───
   Controlled: open / onOpenChange. Same grid animation core. */
const Collapsible = ({ open, onOpenChange, trigger, count, children, className = '' }) => {
  const contentId = adUseId('clp');
  return (
    <div className={`ad-clp${open ? ' is-open' : ''} ${className}`}>
      <button
        type="button"
        className="ad-clp__trigger"
        aria-expanded={!!open}
        aria-controls={contentId}
        onClick={() => onOpenChange && onOpenChange(!open)}
      >
        <AdDisclosureChevron className="ad-clp__chevron" />
        <span>{trigger}</span>
        {count != null && <span className="ad-clp__count">{count}</span>}
      </button>
      <div id={contentId} className="ad-clp__content">
        <div className="ad-clp__inner">
          <div className="ad-clp__pad">{children}</div>
        </div>
      </div>
    </div>
  );
};

/* ─── Tabs ───
   tabs = [{ value, label, badge?, disabled?, content? }]
   APG tabs: roving tabindex, automatic activation by default,
   activationMode="manual" → Enter/Space activates. The 2px
   primary-600 indicator slides between tabs (offsetLeft/Width
   measured, transitioned over --duration-8 --ease-out). */
const Tabs = ({
  tabs = [], value: valueProp, defaultValue, onValueChange,
  variant = 'underline', orientation = 'horizontal',
  activationMode = 'automatic', children, className = '',
}) => {
  const controlled = valueProp !== undefined;
  const firstEnabled = (tabs.find((t) => !t.disabled) || tabs[0] || {}).value;
  const [valueState, setValueState] = React.useState(defaultValue !== undefined ? defaultValue : firstEnabled);
  const value = controlled ? valueProp : valueState;
  const setValue = (v) => {
    if (!controlled) setValueState(v);
    if (onValueChange) onValueChange(v);
  };

  const baseId = adUseId('tabs');
  const tabRefs = React.useRef([]);
  const selectedIndex = Math.max(0, tabs.findIndex((t) => t.value === value));
  const [focusIndex, setFocusIndex] = React.useState(selectedIndex);
  const [indicator, setIndicator] = React.useState(null);
  const vertical = orientation === 'vertical';

  React.useLayoutEffect(() => {
    const el = tabRefs.current[selectedIndex];
    if (!el) return;
    setIndicator(vertical
      ? { top: el.offsetTop, height: el.offsetHeight }
      : { left: el.offsetLeft, width: el.offsetWidth });
  }, [value, tabs.length, orientation, variant]);

  const isEnabled = (i) => tabs[i] && !tabs[i].disabled;
  const step = (from, dir) => {
    let i = from;
    for (let k = 0; k < tabs.length; k++) {
      i = (i + dir + tabs.length) % tabs.length;
      if (isEnabled(i)) return i;
    }
    return from;
  };
  const focusTab = (i) => {
    setFocusIndex(i);
    const el = tabRefs.current[i];
    if (el) el.focus();
    if (activationMode === 'automatic') setValue(tabs[i].value);
  };

  const onListKeyDown = (e) => {
    const nextKey = vertical ? 'ArrowDown' : 'ArrowRight';
    const prevKey = vertical ? 'ArrowUp' : 'ArrowLeft';
    if (e.key === nextKey) { e.preventDefault(); focusTab(step(focusIndex, 1)); }
    else if (e.key === prevKey) { e.preventDefault(); focusTab(step(focusIndex, -1)); }
    else if (e.key === 'Home') { e.preventDefault(); focusTab(step(-1, 1)); }
    else if (e.key === 'End') { e.preventDefault(); focusTab(step(tabs.length, -1)); }
    else if ((e.key === 'Enter' || e.key === ' ') && activationMode === 'manual') {
      e.preventDefault();
      if (isEnabled(focusIndex)) setValue(tabs[focusIndex].value);
    }
  };

  const active = tabs[selectedIndex] || {};
  return (
    <div className={`ad-tabs ad-tabs--${variant}${vertical ? ' ad-tabs--vertical' : ''} ${className}`}>
      <div
        role="tablist"
        aria-orientation={orientation}
        className={`ad-tabs__list${vertical ? '' : ' ad-scroll'}`}
        onKeyDown={onListKeyDown}
      >
        {tabs.map((t, i) => (
          <button
            key={t.value}
            type="button"
            ref={(el) => { tabRefs.current[i] = el; }}
            role="tab"
            id={`${baseId}-tab-${i}`}
            aria-selected={t.value === value}
            aria-controls={`${baseId}-panel-${i}`}
            tabIndex={i === focusIndex ? 0 : -1}
            disabled={t.disabled}
            className={`ad-tabs__tab${t.value === value ? ' is-active' : ''}`}
            onClick={() => { setFocusIndex(i); setValue(t.value); }}
            onFocus={() => setFocusIndex(i)}
          >
            {t.label}
            {t.badge != null && <span className="ad-tabs__badge">{t.badge}</span>}
          </button>
        ))}
        {indicator && <span className="ad-tabs__indicator" aria-hidden="true" style={indicator} />}
      </div>
      <div
        key={value}
        role="tabpanel"
        id={`${baseId}-panel-${selectedIndex}`}
        aria-labelledby={`${baseId}-tab-${selectedIndex}`}
        tabIndex={0}
        className="ad-tabs__panel"
      >
        {active.content !== undefined ? active.content : children}
      </div>
    </div>
  );
};

Object.assign(window, { Accordion, Collapsible, Tabs });
