// <Badge> — a labelled status pill, the "next to the thing it affects"
// building block for the per-agent terminal redesign.
// Design-guide anti-example this exists to fix: the agent page's model/
// effort *pickers* used to live in a `⋯` overflow menu while the current
// model/effort only showed as a separate, non-interactive chip — control
// disconnected from display. `Badge` is that chip PLUS, optionally, the
// control: pass `onClick` and it renders as a real `<button>` (so it can
// open a `Dropdown` right underneath itself, or toggle in place — e.g.
// pause/resume), pass nothing and it stays a plain status `<span>` (e.g.
// "alive"). Same component either way so a page reads as one consistent
// row of badges regardless of which ones happen to be interactive.
//
// Formerly two components: swarm-ui had its own presentational-only
// `StatusChip`, a strict subset of this shape (no interactivity, no
// label/value split, no icon). Deleted in favour of this one — a
// non-interactive `Badge` renders identically, and having two components
// for the same visual pill just meant a page had to pick between them
// with no real distinction to justify it. Lives in `shared` because both
// swarm-ui *and* the per-agent page need the interactive shape, and
// `shared` is the one package both already depend on (see
// `docs/web-ui/design-guide.md`'s component-first + junk-drawer rules).
import type { ComponentChildren } from 'preact';
import './Badge.css';

export type BadgeTone = 'neutral' | 'positive' | 'warning' | 'negative' | 'accent';

export interface BadgeProps {
  /** Dim prefix text, e.g. "model". Omit for a single-value badge like "alive". */
  label?: ComponentChildren;
  /** The value itself, e.g. "sonnet". Required — a badge always shows something. */
  value: ComponentChildren;
  tone?: BadgeTone;
  /** Decorative glyph before the label; `aria-hidden`, the text is still the real label. */
  icon?: ComponentChildren;
  /**
   * Present → renders a `<button>` (real control, min touch target) and
   * shows a disclosure caret. Absent → renders a plain `<span>` (status
   * display only, e.g. "alive"/"idle 6m").
   */
  onClick?: (e: MouseEvent) => void;
  /** Only meaningful with `onClick` — drives the caret direction + `aria-expanded`. */
  expanded?: boolean;
  disabled?: boolean;
  class?: string;
  title?: string;
}

export function Badge({
  label,
  value,
  tone = 'neutral',
  icon,
  onClick,
  expanded,
  disabled,
  class: extraClass,
  title,
}: BadgeProps) {
  const classes = ['ui-badge', `ui-badge-${tone}`, onClick && 'ui-badge-interactive', extraClass]
    .filter(Boolean)
    .join(' ');
  const content = (
    <>
      {icon ? (
        <span class="ui-badge-icon" aria-hidden="true">
          {icon}
        </span>
      ) : null}
      {label ? <span class="ui-badge-label">{label}</span> : null}
      <span class="ui-badge-value">{value}</span>
      {onClick ? (
        <span class="ui-badge-caret" aria-hidden="true">
          {expanded ? '▴' : '▾'}
        </span>
      ) : null}
    </>
  );
  if (onClick) {
    return (
      <button
        type="button"
        class={classes}
        onClick={onClick}
        disabled={disabled}
        aria-expanded={expanded}
        title={title}
      >
        {content}
      </button>
    );
  }
  return (
    <span class={classes} title={title}>
      {content}
    </span>
  );
}
