/* Starboard · Buttons family
   Button, ButtonGroup (attached + segmented), Toggle, ToggleGroup.
   Load with: <script type="text/babel" src="Buttons.jsx"></script>
   Requires: React 18, buttons.css, a11y.js */

// ─── Button ───
const Button = ({
  variant = 'primary', size = 'md', disabled, loading, iconOnly,
  leadingIcon, trailingIcon, children, onClick, type = 'button',
  className = '', ...rest
}) => {
  if (iconOnly && !rest['aria-label']) {
    console.warn('Starboard Button: iconOnly buttons require an aria-label.');
  }
  const cls = [
    'ad-btn',
    `ad-btn--${variant}`,
    size !== 'md' && `ad-btn--${size}`,
    iconOnly && 'ad-btn--icon',
    loading && 'is-loading',
    className,
  ].filter(Boolean).join(' ');
  return (
    <button
      type={type}
      className={cls}
      disabled={disabled}
      aria-busy={loading || undefined}
      aria-disabled={disabled || undefined}
      onClick={loading ? undefined : onClick}
      {...rest}
    >
      {loading && <span className="ad-btn__spinner" aria-hidden="true" />}
      {leadingIcon && <span className="ad-btn__icon" aria-hidden="true">{leadingIcon}</span>}
      {children != null && <span className="ad-btn__label">{children}</span>}
      {trailingIcon && <span className="ad-btn__icon" aria-hidden="true">{trailingIcon}</span>}
    </button>
  );
};

// ─── ButtonGroup ───
// Attached mode: pass Button children — they fuse into one control.
// Segmented mode: pass `segmented` + options [{value, label, disabled}],
// `value`, `onChange` — a single-select control of aria-pressed buttons.
const ButtonGroup = ({
  segmented, options = [], value, onChange,
  size = 'md', ariaLabel, children, className = '',
}) => {
  if (!segmented) {
    return (
      <div className={`ad-btngrp ${className}`} role="group" aria-label={ariaLabel}>
        {children}
      </div>
    );
  }
  return (
    <div
      className={`ad-seg${size === 'sm' ? ' ad-seg--sm' : ''} ${className}`}
      role="group"
      aria-label={ariaLabel}
    >
      {options.map((opt) => (
        <button
          key={opt.value}
          type="button"
          className="ad-seg__btn"
          aria-pressed={value === opt.value}
          disabled={opt.disabled}
          onClick={() => onChange && onChange(opt.value)}
        >
          {opt.icon && <span className="ad-btn__icon" aria-hidden="true">{opt.icon}</span>}
          {opt.label}
        </button>
      ))}
    </div>
  );
};

// ─── Toggle — a pressed-state button (aria-pressed) ───
const Toggle = ({
  pressed, onPressedChange, disabled, size = 'md', iconOnly,
  children, className = '', ...rest
}) => (
  <button
    type="button"
    className={[
      'ad-toggle',
      size !== 'md' && `ad-toggle--${size}`,
      iconOnly && 'ad-toggle--icon',
      className,
    ].filter(Boolean).join(' ')}
    aria-pressed={!!pressed}
    disabled={disabled}
    onClick={() => onPressedChange && onPressedChange(!pressed)}
    {...rest}
  >
    {children}
  </button>
);

// ─── ToggleGroup — single / multiple selection, roving tabindex ───
// type="single": value is a string (or null). type="multiple": value is array.
const ToggleGroup = ({
  type = 'single', value, onChange, options = [],
  size = 'md', ariaLabel, className = '',
}) => {
  const roving = adUseRovingTabindex(options.length, { orientation: 'horizontal', loop: true });
  const itemRefs = React.useRef([]);
  const moved = React.useRef(false);

  React.useEffect(() => {
    if (!moved.current) return;
    const el = itemRefs.current[roving.index];
    if (el) el.focus();
  }, [roving.index]);

  const isOn = (v) => (type === 'multiple' ? (value || []).includes(v) : value === v);
  const toggle = (v) => {
    if (!onChange) return;
    if (type === 'multiple') {
      const cur = value || [];
      onChange(cur.includes(v) ? cur.filter((x) => x !== v) : [...cur, v]);
    } else {
      onChange(value === v ? null : v);
    }
  };

  return (
    <div
      className={`ad-tglgrp ${className}`}
      role="group"
      aria-label={ariaLabel}
      onKeyDown={(e) => { moved.current = true; roving.onKeyDown(e); }}
    >
      {options.map((opt, i) => (
        <button
          key={opt.value}
          ref={(el) => { itemRefs.current[i] = el; }}
          type="button"
          className={[
            'ad-toggle',
            size !== 'md' && `ad-toggle--${size}`,
            opt.iconOnly && 'ad-toggle--icon',
          ].filter(Boolean).join(' ')}
          aria-pressed={isOn(opt.value)}
          aria-label={opt.iconOnly ? opt.label : undefined}
          disabled={opt.disabled}
          {...roving.itemProps(i)}
          onFocus={() => roving.setIndex(i)}
          onClick={() => toggle(opt.value)}
        >
          {opt.icon && <span className="ad-btn__icon" aria-hidden="true">{opt.icon}</span>}
          {!opt.iconOnly && opt.label}
        </button>
      ))}
    </div>
  );
};

// Export
Object.assign(window, { Button, ButtonGroup, Toggle, ToggleGroup });
