// Small shared primitives: icons, badges, sparklines, avatars
const { useState, useEffect, useRef, useMemo, useCallback } = React;

// Line icons — simple stroke icons built from SVG paths
function Icon({ name, size = 16, stroke = 1.5 }) {
  const props = {
    width: size, height: size, viewBox: "0 0 24 24",
    fill: "none", stroke: "currentColor", strokeWidth: stroke,
    strokeLinecap: "round", strokeLinejoin: "round"
  };
  const paths = {
    home:       <><path d="M3 11l9-7 9 7"/><path d="M5 10v10h14V10"/></>,
    calendar:   <><rect x="3" y="4" width="18" height="17" rx="2"/><path d="M3 9h18M8 2v4M16 2v4"/></>,
    users:      <><circle cx="9" cy="8" r="3.5"/><path d="M2.5 20c.6-3.4 3.4-5.5 6.5-5.5s5.9 2.1 6.5 5.5"/><circle cx="17" cy="7" r="2.5"/><path d="M21.5 16.5c-.4-2.1-1.9-3.6-4-4"/></>,
    coin:       <><ellipse cx="12" cy="7" rx="8" ry="3"/><path d="M4 7v10c0 1.66 3.58 3 8 3s8-1.34 8-3V7"/><path d="M4 12c0 1.66 3.58 3 8 3s8-1.34 8-3"/></>,
    shield:     <><path d="M12 3l8 3v6c0 4.5-3.5 8.5-8 9-4.5-.5-8-4.5-8-9V6l8-3z"/><path d="M9 12l2 2 4-4"/></>,
    search:     <><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></>,
    bell:       <><path d="M6 8a6 6 0 1112 0c0 7 3 8 3 8H3s3-1 3-8z"/><path d="M10 20a2 2 0 004 0"/></>,
    sparkle:    <><path d="M12 3v4M12 17v4M3 12h4M17 12h4M6 6l2.5 2.5M15.5 15.5L18 18M18 6l-2.5 2.5M8.5 15.5L6 18"/></>,
    filter:     <><path d="M3 5h18M6 12h12M10 19h4"/></>,
    plus:       <><path d="M12 5v14M5 12h14"/></>,
    arrowRight: <><path d="M5 12h14M13 6l6 6-6 6"/></>,
    chevronDown:<><path d="M6 9l6 6 6-6"/></>,
    chevronRight:<><path d="M9 6l6 6-6 6"/></>,
    check:      <><path d="M5 12l5 5L20 7"/></>,
    x:          <><path d="M6 6l12 12M18 6L6 18"/></>,
    alert:      <><path d="M12 3l10 18H2L12 3z"/><path d="M12 10v5M12 18v.01"/></>,
    lock:       <><rect x="4" y="11" width="16" height="10" rx="2"/><path d="M8 11V8a4 4 0 018 0v3"/></>,
    eye:        <><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></>,
    more:       <><circle cx="5"  cy="12" r="1"/><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/></>,
    command:    <><path d="M7 7h10v10H7z"/><path d="M4 7h3v3H4a1.5 1.5 0 010-3zM17 7h3a1.5 1.5 0 010 3h-3V7zM4 14h3v3a1.5 1.5 0 01-3 0v-3zM17 14h3v3a1.5 1.5 0 01-3 0v-3z" transform="translate(0 0)"/></>,
    clock:      <><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></>,
    link:       <><path d="M10 14a5 5 0 007 0l3-3a5 5 0 10-7-7l-1 1"/><path d="M14 10a5 5 0 00-7 0l-3 3a5 5 0 107 7l1-1"/></>,
    download:   <><path d="M12 3v12M6 11l6 6 6-6"/><path d="M5 21h14"/></>,
    mic:        <><rect x="9" y="3" width="6" height="11" rx="3"/><path d="M5 11a7 7 0 0014 0M12 18v3"/></>,
    settings:   <><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 00.3 1.8l.1.1a2 2 0 11-2.8 2.8l-.1-.1a1.7 1.7 0 00-1.8-.3 1.7 1.7 0 00-1 1.5V21a2 2 0 01-4 0v-.1a1.7 1.7 0 00-1-1.5 1.7 1.7 0 00-1.8.3l-.1.1a2 2 0 11-2.8-2.8l.1-.1a1.7 1.7 0 00.3-1.8 1.7 1.7 0 00-1.5-1H3a2 2 0 010-4h.1a1.7 1.7 0 001.5-1 1.7 1.7 0 00-.3-1.8l-.1-.1a2 2 0 112.8-2.8l.1.1a1.7 1.7 0 001.8.3h.1a1.7 1.7 0 001-1.5V3a2 2 0 014 0v.1a1.7 1.7 0 001 1.5 1.7 1.7 0 001.8-.3l.1-.1a2 2 0 112.8 2.8l-.1.1a1.7 1.7 0 00-.3 1.8v.1a1.7 1.7 0 001.5 1H21a2 2 0 010 4h-.1a1.7 1.7 0 00-1.5 1z"/></>,
    trend:      <><path d="M3 17l6-6 4 4 8-8"/><path d="M15 7h6v6"/></>,
    wand:       <><path d="M15 4V2M15 10V8M19 6h2M11 6h2"/><path d="M9 16l-5 5M13 12l7 7"/></>,
  };
  return <svg {...props}>{paths[name] || <circle cx="12" cy="12" r="8"/>}</svg>;
}

function Badge({ tone="default", children, dot=false }) {
  return (
    <span className="badge" data-tone={tone === "default" ? undefined : tone}>
      {dot && <span className="dot" />}
      {children}
    </span>
  );
}

function AvatarInitials({ name, tone="ink", size }) {
  const initials = name.split(/\s+/).slice(0,2).map(p => p[0]).join("").toUpperCase();
  return <div className="avatar" data-tone={tone} style={size ? { width: size, height: size, fontSize: size*0.38 } : null}>{initials}</div>;
}

function Person({ name, meta, tone="ink" }) {
  return (
    <div className="person">
      <AvatarInitials name={name} tone={tone} />
      <div>
        <div className="person-name">{name}</div>
        {meta && <div className="person-meta">{meta}</div>}
      </div>
    </div>
  );
}

function Sparkline({ points, color="var(--ink)", fill=null, height=44 }) {
  const width = 200;
  const { path } = spark(points, { width, height });
  const filledPath = fill ? path + ` L${width},${height} L0,${height} Z` : null;
  return (
    <svg className="spark" viewBox={`0 0 ${width} ${height}`} preserveAspectRatio="none">
      {filledPath && <path d={filledPath} fill={fill} opacity="0.15" />}
      <path d={path} stroke={color} strokeWidth="1.25" fill="none" />
    </svg>
  );
}

function Bars({ values, highlightIdx=-1, height=60 }) {
  const max = Math.max(...values);
  return (
    <div className="bars" style={{ height }}>
      {values.map((v, i) => (
        <i key={i} data-hi={i === highlightIdx} style={{ height: `${(v/max)*100}%` }} />
      ))}
    </div>
  );
}

function Ring({ pct = 1, size = 72, stroke = 6, color = "var(--sage)", track = "var(--line)", label }) {
  const r = (size - stroke) / 2;
  const c = 2 * Math.PI * r;
  const offset = c * (1 - pct);
  return (
    <div className="ring" style={{ width: size, height: size }}>
      <svg width={size} height={size}>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke={track} strokeWidth={stroke} />
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke={color} strokeWidth={stroke}
          strokeDasharray={c} strokeDashoffset={offset} strokeLinecap="round" />
      </svg>
      {label != null && <div className="ring-label">{label}</div>}
    </div>
  );
}

// Tier — Gartner-aligned agent autonomy tiers. L1 Shadow, L2 Suggest, L3 Act w/ approval, L4 Autonomous-with-limits.
function TierBadge({ tier = "L2", size = "sm" }) {
  const def = {
    L1: { label: "L1 Shadow",         tone: "ink"  },
    L2: { label: "L2 Suggest",        tone: "ai"   },
    L3: { label: "L3 Act + approve",  tone: "warn" },
    L4: { label: "L4 Autonomous",     tone: "ok"   },
  }[tier] || { label: tier, tone: "ink" };
  return <span className={`tier-badge tier-${def.tone}`} data-size={size}>{def.label}</span>;
}

function ConfidencePill({ value = 0.9, size = "sm" }) {
  const pct = Math.round(value * 100);
  const tone = pct >= 95 ? "ok" : pct >= 80 ? "warn" : "block";
  return (
    <span className="conf-pill" data-tone={tone} data-size={size} title={`Confidence ${pct}%`}>
      <span className="conf-dot" />
      {pct}%
    </span>
  );
}

function AIChip({ children, onClick, tier, confidence }) {
  return (
    <button className="ai-inline" onClick={onClick}>
      <span className="sparkle" />
      {children}
      {tier && <TierBadge tier={tier} />}
      {confidence != null && <ConfidencePill value={confidence} />}
    </button>
  );
}

// Gate — small inline marker showing whether an entity clears a compliance checkpoint.
// Used throughout lists/tables/shifts so users can see gate state at a glance.
function Gate({ tone = "ok", title }) {
  return (
    <span className="gate" data-tone={tone} title={title || (tone === "ok" ? "Compliance clear" : tone === "warn" ? "Compliance warning" : "Compliance blocked")}>
      <Icon name={tone === "ok" ? "check" : tone === "warn" ? "alert" : "lock"} size={10} stroke={2} />
    </span>
  );
}

function GateInline({ tone = "ok", label }) {
  return (
    <span className="gate-inline" data-tone={tone}>
      <Icon name={tone === "ok" ? "check" : tone === "warn" ? "alert" : "lock"} size={9} stroke={2} />
      {label}
    </span>
  );
}

function Chain({ steps }) {
  return (
    <div className="chain">
      {steps.map((s, i) => (
        <React.Fragment key={i}>
          <span className="chain-step">{s}</span>
          {i < steps.length - 1 && <span className="chain-arrow">→</span>}
        </React.Fragment>
      ))}
    </div>
  );
}

// Modal — backdrop + centred card + Esc-to-close.
function Modal({ open, onClose, title, children, footer, width = 560 }) {
  React.useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === "Escape") onClose && onClose(); };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" style={{ width }} onClick={(e) => e.stopPropagation()} role="dialog" aria-modal="true">
        <div className="modal-head">
          <div className="card-title" style={{ fontSize: 14 }}>{title}</div>
          <button className="icon-btn" onClick={onClose} aria-label="Close"><Icon name="x" size={12} /></button>
        </div>
        <div className="modal-body">{children}</div>
        {footer && <div className="modal-foot">{footer}</div>}
      </div>
    </div>
  );
}

// Drawer — right-side slide-in used for shift / employee / plan detail.
function Drawer({ open, onClose, title, subtitle, children, footer, width = 420 }) {
  React.useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === "Escape") onClose && onClose(); };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div className="drawer-backdrop" onClick={onClose}>
      <div className="drawer" style={{ width }} onClick={(e) => e.stopPropagation()} role="dialog" aria-modal="true">
        <div className="drawer-head">
          <div>
            <div className="card-title" style={{ fontSize: 14 }}>{title}</div>
            {subtitle && <div className="sub" style={{ marginTop: 2 }}>{subtitle}</div>}
          </div>
          <button className="icon-btn" onClick={onClose} aria-label="Close"><Icon name="x" size={12} /></button>
        </div>
        <div className="drawer-body">{children}</div>
        {footer && <div className="drawer-foot">{footer}</div>}
      </div>
    </div>
  );
}

// Toast stack — fed by state.toasts.
function ToastStack({ toasts, onDismiss }) {
  return (
    <div className="toast-stack" aria-live="polite">
      {toasts.map(t => (
        <div key={t.id} className="toast" data-tone={t.tone || "ok"}>
          <Icon name={t.icon || (t.tone === "block" ? "alert" : t.tone === "ai" ? "sparkle" : "check")} size={14} />
          <div style={{ flex: 1 }}>{t.text}</div>
          <button className="icon-btn" onClick={() => onDismiss(t.id)} aria-label="Dismiss"><Icon name="x" size={10} /></button>
        </div>
      ))}
    </div>
  );
}

// Dropdown — click-outside aware.
function Dropdown({ trigger, children, align = "left" }) {
  const [open, setOpen] = React.useState(false);
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!open) return;
    const onClick = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", onClick);
    return () => document.removeEventListener("mousedown", onClick);
  }, [open]);
  const close = () => setOpen(false);
  return (
    <div className="dropdown-wrap" ref={ref}>
      <div onClick={() => setOpen(o => !o)}>{trigger}</div>
      {open && (
        <div className="dropdown" data-align={align} onClick={(e) => e.stopPropagation()}>
          {typeof children === "function" ? children(close) : children}
        </div>
      )}
    </div>
  );
}

function DropdownItem({ icon, label, onClick, tone }) {
  return (
    <div className="dropdown-item" data-tone={tone} onClick={onClick}>
      {icon && <Icon name={icon} size={13} />}
      <span>{label}</span>
    </div>
  );
}

// TextInput — labeled input used in forms.
function TextInput({ label, value, onChange, placeholder, type = "text", autoFocus, name, id }) {
  return (
    <label style={{ display: "block" }}>
      {label && <div className="eyebrow" style={{ marginBottom: 4 }}>{label}</div>}
      <input
        className="input"
        id={id} name={name}
        type={type}
        autoFocus={autoFocus}
        placeholder={placeholder}
        value={value}
        onChange={(e) => onChange(e.target.value)}
      />
    </label>
  );
}

// SearchInput — icon + input with optional clear.
function SearchInput({ placeholder = "Search", value, onChange, kbd, onFocus }) {
  return (
    <div className="search-input" onClick={(e) => { const inp = e.currentTarget.querySelector("input"); inp && inp.focus(); }}>
      <Icon name="search" size={13} />
      <input
        placeholder={placeholder}
        value={value}
        onChange={(e) => onChange(e.target.value)}
        onFocus={onFocus}
      />
      {value ? (
        <button className="icon-btn" style={{ width: 22, height: 22 }} onClick={(e) => { e.stopPropagation(); onChange(""); }}>
          <Icon name="x" size={11} />
        </button>
      ) : (kbd ? <kbd style={{ fontFamily: "var(--font-mono)", fontSize: 10, border: "1px solid var(--line)", borderRadius: 3, padding: "0 4px", color: "var(--ink-4)", background: "var(--bone)" }}>{kbd}</kbd> : null)}
    </div>
  );
}

Object.assign(window, {
  Icon, Badge, AvatarInitials, Person, Sparkline, Bars, Ring, AIChip, Chain, Gate, GateInline,
  TierBadge, ConfidencePill,
  Modal, Drawer, ToastStack, Dropdown, DropdownItem, TextInput, SearchInput,
});
