/* ============================================================
   F2 UI — Data display library
   Avatar · AvatarGroup · List · Timeline · Stat · Progress ·
   Skeleton · EmptyState · CodeBlock · Accordion · DataTable
   ============================================================ */
(function () {
  const { Icon, Checkbox } = window.F2;
  const { injectCss, highlight } = window.SB;

  const STATUS = { neutral: 'var(--f2-gray-400)', active: 'var(--f2-accent)', success: 'var(--f2-success)', warning: 'var(--f2-warning)', error: 'var(--f2-error)' };

  /* ====================== Avatar ====================== */
  function initials(name) { return (name || '').split(/\s+/).filter(Boolean).slice(0, 2).map((w) => w[0]).join('').toUpperCase(); }
  function Avatar({ src, name = '', size = 40, shape = 'circle', status, style = {} }) {
    const radius = shape === 'circle' ? '50%' : 'var(--f2-radius-control)';
    return (
      <span style={{ position: 'relative', display: 'inline-flex', width: size, height: size, flex: '0 0 auto', ...style }}>
        {src
          ? <img src={src} alt={name} style={{ width: size, height: size, borderRadius: radius, objectFit: 'cover', border: '1px solid var(--f2-border)' }} />
          : <span style={{ width: size, height: size, borderRadius: radius, display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
              background: 'var(--f2-surface-raised)', border: '1px solid var(--f2-border-strong)', color: 'var(--f2-text-secondary)',
              fontFamily: 'var(--f2-font-mono)', fontWeight: 600, fontSize: size * 0.36, letterSpacing: '0.02em' }}>{initials(name) || '—'}</span>}
        {status && <span style={{ position: 'absolute', right: -1, bottom: -1, width: Math.max(8, size * 0.26), height: Math.max(8, size * 0.26), borderRadius: '50%', background: STATUS[status] || STATUS.neutral, border: '2px solid var(--f2-surface)' }} />}
      </span>
    );
  }
  function AvatarGroup({ people = [], size = 36, max = 4, style = {} }) {
    const shown = people.slice(0, max); const extra = people.length - shown.length;
    return (
      <div style={{ display: 'inline-flex', alignItems: 'center', ...style }}>
        {shown.map((p, i) => <span key={i} style={{ marginLeft: i ? -size * 0.3 : 0, borderRadius: '50%', boxShadow: '0 0 0 2px var(--f2-surface)' }}><Avatar {...p} size={size} /></span>)}
        {extra > 0 && <span style={{ marginLeft: -size * 0.3, width: size, height: size, borderRadius: '50%', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', background: 'var(--f2-surface-card)', border: '1px solid var(--f2-border-strong)', boxShadow: '0 0 0 2px var(--f2-surface)', color: 'var(--f2-text-muted)', fontFamily: 'var(--f2-font-mono)', fontSize: size * 0.32 }}>+{extra}</span>}
      </div>
    );
  }

  /* ====================== List ====================== */
  function List({ items = [], divided = true, style = {} }) {
    return (
      <ul style={{ margin: 0, padding: 0, listStyle: 'none', border: '1px solid var(--f2-border)', borderRadius: 'var(--f2-radius-md)', overflow: 'hidden', background: 'var(--f2-surface-card)', ...style }}>
        {items.map((it, i) => (
          <li key={i} style={{ display: 'flex', alignItems: 'center', gap: 13, padding: '13px 16px', borderTop: divided && i ? '1px solid var(--f2-border)' : 'none' }}>
            {it.leading}
            {it.icon && !it.leading && <span style={{ color: 'var(--f2-text-muted)', flex: '0 0 auto' }}><Icon name={it.icon} size={18} /></span>}
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 14.5, color: 'var(--f2-text)', fontWeight: 500 }}>{it.title}</div>
              {it.subtitle && <div style={{ fontSize: 13, color: 'var(--f2-text-muted)', marginTop: 2, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{it.subtitle}</div>}
            </div>
            {it.meta && <span style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 12, color: 'var(--f2-text-faint)', flex: '0 0 auto' }}>{it.meta}</span>}
            {it.action}
          </li>
        ))}
      </ul>
    );
  }

  /* ====================== Timeline ====================== */
  function Timeline({ items = [], style = {} }) {
    return (
      <ol style={{ margin: 0, padding: 0, listStyle: 'none', ...style }}>
        {items.map((it, i) => {
          const last = i === items.length - 1;
          const c = STATUS[it.tone] || 'var(--f2-border-strong)';
          const lit = it.tone && it.tone !== 'neutral';
          return (
            <li key={i} style={{ display: 'flex', gap: 14 }}>
              <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
                <span style={{ width: 26, height: 26, flex: '0 0 auto', borderRadius: '50%', display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                  background: lit ? 'var(--f2-surface-accent)' : 'var(--f2-surface-card)', border: `1px solid ${lit ? c : 'var(--f2-border-strong)'}`, color: c }}>
                  {it.icon ? <Icon name={it.icon} size={13} /> : <span style={{ width: 7, height: 7, borderRadius: '50%', background: c }} />}
                </span>
                {!last && <span style={{ width: 1, flex: 1, minHeight: 24, background: 'var(--f2-border)', margin: '4px 0' }} />}
              </div>
              <div style={{ paddingBottom: last ? 0 : 22, flex: 1 }}>
                <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, flexWrap: 'wrap' }}>
                  <span style={{ fontSize: 14.5, fontWeight: 500, color: 'var(--f2-text)' }}>{it.title}</span>
                  {it.time && <span style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 11.5, color: 'var(--f2-text-faint)' }}>{it.time}</span>}
                </div>
                {it.description && <div style={{ fontSize: 13.5, color: 'var(--f2-text-muted)', marginTop: 3, lineHeight: 1.5 }}>{it.description}</div>}
              </div>
            </li>
          );
        })}
      </ol>
    );
  }

  /* ====================== Stat ====================== */
  function Stat({ label, value, delta, deltaTone = 'auto', hint, icon, style = {} }) {
    let tone = deltaTone;
    if (deltaTone === 'auto' && typeof delta === 'string') tone = delta.trim().startsWith('-') ? 'down' : 'up';
    const dc = tone === 'down' ? 'var(--f2-error)' : tone === 'up' ? 'var(--f2-success)' : 'var(--f2-text-muted)';
    return (
      <div style={{ ...style }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          {icon && <span style={{ color: 'var(--f2-text-muted)' }}><Icon name={icon} size={15} /></span>}
          <span style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 11, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--f2-text-muted)' }}>{label}</span>
        </div>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginTop: 8 }}>
          <span style={{ fontFamily: 'var(--f2-font-display)', fontWeight: 700, fontSize: 32, letterSpacing: '-0.03em', color: 'var(--f2-text)' }}>{value}</span>
          {delta != null && <span style={{ display: 'inline-flex', alignItems: 'center', gap: 3, fontFamily: 'var(--f2-font-mono)', fontSize: 12.5, color: dc }}>
            {tone !== 'flat' && <Icon name={tone === 'down' ? 'TrendingDown' : 'TrendingUp'} size={13} />}{delta}
          </span>}
        </div>
        {hint && <div style={{ fontSize: 12.5, color: 'var(--f2-text-faint)', marginTop: 4 }}>{hint}</div>}
      </div>
    );
  }

  /* ====================== Progress ====================== */
  injectCss('f2-progress-css', `@keyframes f2-indet{0%{left:-40%}100%{left:100%}}@media (prefers-reduced-motion: reduce){.f2-indet{animation:none!important;left:0!important;width:100%!important}}`);
  function Progress({ value = 0, max = 100, tone = 'accent', showValue = false, indeterminate = false, size = 'md', style = {} }) {
    const pct = Math.max(0, Math.min(100, (value / max) * 100));
    const h = size === 'sm' ? 4 : size === 'lg' ? 10 : 6;
    const fill = tone === 'success' ? 'var(--f2-success)' : tone === 'warning' ? 'var(--f2-warning)' : tone === 'error' ? 'var(--f2-error)' : 'var(--f2-accent)';
    return (
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, ...style }}>
        <div role="progressbar" aria-valuenow={indeterminate ? undefined : Math.round(pct)} aria-valuemin={0} aria-valuemax={100}
          style={{ position: 'relative', flex: 1, height: h, borderRadius: 999, background: 'var(--f2-surface-sunken)', overflow: 'hidden' }}>
          {indeterminate
            ? <span className="f2-indet" style={{ position: 'absolute', top: 0, bottom: 0, width: '40%', borderRadius: 999, background: fill, animation: 'f2-indet 1.3s var(--f2-ease) infinite' }} />
            : <span style={{ position: 'absolute', top: 0, left: 0, bottom: 0, width: `${pct}%`, borderRadius: 999, background: fill, transition: 'width var(--f2-dur-base) var(--f2-ease)' }} />}
        </div>
        {showValue && <span style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 12, color: 'var(--f2-text-secondary)', width: 38, textAlign: 'right' }}>{Math.round(pct)}%</span>}
      </div>
    );
  }

  /* ====================== Skeleton ====================== */
  injectCss('f2-skeleton-css', `@keyframes f2-pulse{0%,100%{opacity:.5}50%{opacity:.9}}@media (prefers-reduced-motion: reduce){.f2-sk{animation:none!important}}`);
  function Skeleton({ width = '100%', height, variant = 'text', radius, style = {} }) {
    const h = height || (variant === 'text' ? 13 : variant === 'circle' ? 40 : 80);
    const w = variant === 'circle' ? h : width;
    const r = radius != null ? radius : (variant === 'circle' ? '50%' : variant === 'text' ? 5 : 'var(--f2-radius-md)');
    return <span className="f2-sk" style={{ display: 'block', width: w, height: h, borderRadius: r, background: 'var(--f2-surface-raised)', animation: 'f2-pulse 1.5s var(--f2-ease) infinite', ...style }} />;
  }

  /* ====================== EmptyState ====================== */
  function EmptyState({ icon = 'Inbox', title, description, action, style = {} }) {
    return (
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', textAlign: 'center', gap: 8, padding: '40px 24px', ...style }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 56, height: 56, borderRadius: 'var(--f2-radius-lg)', border: '1px solid var(--f2-border)', background: 'var(--f2-surface-card)', color: 'var(--f2-text-muted)', marginBottom: 6 }}><Icon name={icon} size={24} stroke={1.5} /></span>
        {title && <div style={{ fontFamily: 'var(--f2-font-display)', fontWeight: 600, fontSize: 17, color: 'var(--f2-text)' }}>{title}</div>}
        {description && <div style={{ fontSize: 14, color: 'var(--f2-text-muted)', maxWidth: 320, lineHeight: 1.55 }}>{description}</div>}
        {action && <div style={{ marginTop: 10 }}>{action}</div>}
      </div>
    );
  }

  /* ====================== CodeBlock ====================== */
  function CodeBlock({ code = '', title, showCopy = true, style = {} }) {
    const [copied, setCopied] = React.useState(false);
    return (
      <div style={{ border: '1px solid var(--f2-border)', borderRadius: 'var(--f2-radius-md)', overflow: 'hidden', background: 'var(--f2-surface-sunken)', ...style }}>
        {(title || showCopy) && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '9px 12px 9px 14px', borderBottom: '1px solid var(--f2-border)', background: 'var(--f2-surface-raised)' }}>
            <span style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 11.5, color: 'var(--f2-text-muted)', flex: 1 }}>{title}</span>
            {showCopy && <button onClick={() => { window.SB.copy(code, (ok) => { setCopied(ok); setTimeout(() => setCopied(false), 1300); }); }} aria-label="Copy code"
              style={{ display: 'inline-flex', alignItems: 'center', gap: 5, background: 'none', border: 'none', cursor: 'pointer', color: copied ? 'var(--f2-accent-text)' : 'var(--f2-text-muted)', fontFamily: 'var(--f2-font-mono)', fontSize: 11 }}>
              <Icon name={copied ? 'Check' : 'Copy'} size={13} />{copied ? 'Copied' : 'Copy'}</button>}
          </div>
        )}
        <pre style={{ margin: 0, padding: '14px 16px', overflowX: 'auto' }}><code style={{ fontFamily: 'var(--f2-font-mono)', fontSize: 13, lineHeight: 1.65, color: 'var(--f2-text-secondary)' }} dangerouslySetInnerHTML={{ __html: highlight(code) }} /></pre>
      </div>
    );
  }

  /* ====================== Accordion ====================== */
  function Accordion({ items = [], allowMultiple = false, defaultOpen = [], style = {} }) {
    const [open, setOpen] = React.useState(() => new Set(defaultOpen));
    function toggle(i) {
      setOpen((prev) => {
        const next = new Set(allowMultiple ? prev : []);
        if (prev.has(i)) next.delete(i); else next.add(i);
        return next;
      });
    }
    return (
      <div style={{ border: '1px solid var(--f2-border)', borderRadius: 'var(--f2-radius-md)', overflow: 'hidden', background: 'var(--f2-surface-card)', ...style }}>
        {items.map((it, i) => {
          const isOpen = open.has(i);
          return (
            <div key={i} style={{ borderTop: i ? '1px solid var(--f2-border)' : 'none' }}>
              <button onClick={() => toggle(i)} aria-expanded={isOpen} style={{
                display: 'flex', alignItems: 'center', gap: 12, width: '100%', textAlign: 'left', padding: '15px 16px', border: 'none', background: 'none', cursor: 'pointer', color: 'var(--f2-text)',
                fontFamily: 'var(--f2-font-display)', fontWeight: 500, fontSize: 15.5,
              }}>
                <span style={{ flex: 1 }}>{it.title}</span>
                <span style={{ color: isOpen ? 'var(--f2-accent-text)' : 'var(--f2-text-muted)', transition: 'transform var(--f2-dur-base) var(--f2-ease)', transform: isOpen ? 'rotate(180deg)' : 'none' }}><Icon name="ChevronDown" size={18} /></span>
              </button>
              <div style={{ display: 'grid', gridTemplateRows: isOpen ? '1fr' : '0fr', transition: 'grid-template-rows var(--f2-dur-base) var(--f2-ease)' }}>
                <div style={{ overflow: 'hidden' }}>
                  <div style={{ padding: '0 16px 16px', fontSize: 14.5, lineHeight: 1.6, color: 'var(--f2-text-secondary)' }}>{it.content}</div>
                </div>
              </div>
            </div>
          );
        })}
      </div>
    );
  }

  /* ====================== DataTable ====================== */
  function DataTable({ columns = [], rows = [], getRowId = (r, i) => i, selectable = false, dense = false, onRowClick, style = {} }) {
    const [sort, setSort] = React.useState({ key: null, dir: 'asc' });
    const [sel, setSel] = React.useState(() => new Set());
    const sorted = React.useMemo(() => {
      if (!sort.key) return rows;
      const col = columns.find((c) => c.key === sort.key);
      const arr = [...rows].sort((a, b) => {
        const va = col && col.sortValue ? col.sortValue(a) : a[sort.key];
        const vb = col && col.sortValue ? col.sortValue(b) : b[sort.key];
        if (va < vb) return -1; if (va > vb) return 1; return 0;
      });
      return sort.dir === 'desc' ? arr.reverse() : arr;
    }, [rows, sort, columns]);
    function toggleSort(c) { if (!c.sortable) return; setSort((s) => s.key === c.key ? { key: c.key, dir: s.dir === 'asc' ? 'desc' : 'asc' } : { key: c.key, dir: 'asc' }); }
    const allIds = sorted.map(getRowId);
    const allSel = allIds.length > 0 && allIds.every((id) => sel.has(id));
    const someSel = allIds.some((id) => sel.has(id)) && !allSel;
    function toggleAll() { setSel(allSel ? new Set() : new Set(allIds)); }
    function toggleRow(id) { setSel((prev) => { const n = new Set(prev); n.has(id) ? n.delete(id) : n.add(id); return n; }); }
    const pad = dense ? '8px 14px' : '13px 16px';
    const th = { padding: dense ? '9px 14px' : '11px 16px', textAlign: 'left', fontFamily: 'var(--f2-font-mono)', fontSize: 10.5, letterSpacing: '0.12em', textTransform: 'uppercase', color: 'var(--f2-text-faint)', fontWeight: 500, whiteSpace: 'nowrap', borderBottom: '1px solid var(--f2-border-strong)', background: 'var(--f2-surface-raised)' };
    return (
      <div style={{ border: '1px solid var(--f2-border)', borderRadius: 'var(--f2-radius-md)', overflow: 'hidden', ...style }}>
        <div style={{ overflowX: 'auto' }}>
          <table style={{ width: '100%', borderCollapse: 'collapse', background: 'var(--f2-surface-card)' }}>
            <thead>
              <tr>
                {selectable && <th style={{ ...th, width: 44 }}><Checkbox checked={allSel} indeterminate={someSel} onChange={toggleAll} /></th>}
                {columns.map((c) => (
                  <th key={c.key} style={{ ...th, textAlign: c.align || 'left', width: c.width, cursor: c.sortable ? 'pointer' : 'default' }} onClick={() => toggleSort(c)} aria-sort={sort.key === c.key ? (sort.dir === 'asc' ? 'ascending' : 'descending') : undefined}>
                    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, justifyContent: c.align === 'right' ? 'flex-end' : 'flex-start' }}>
                      {c.header}
                      {c.sortable && <span style={{ color: sort.key === c.key ? 'var(--f2-accent-text)' : 'var(--f2-text-faint)', display: 'inline-flex' }}><Icon name={sort.key === c.key ? (sort.dir === 'asc' ? 'ChevronUp' : 'ChevronDown') : 'ChevronsUpDown'} size={13} /></span>}
                    </span>
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              {sorted.map((r, i) => {
                const id = getRowId(r, i); const isSel = sel.has(id);
                return (
                  <tr key={id} onClick={() => onRowClick && onRowClick(r)} style={{ borderBottom: i === sorted.length - 1 ? 'none' : '1px solid var(--f2-border)', background: isSel ? 'var(--f2-surface-accent)' : 'transparent', cursor: onRowClick ? 'pointer' : 'default', transition: 'background var(--f2-dur-fast) var(--f2-ease)' }}
                    onMouseEnter={(e) => { if (!isSel) e.currentTarget.style.background = 'var(--f2-surface-raised)'; }}
                    onMouseLeave={(e) => { if (!isSel) e.currentTarget.style.background = 'transparent'; }}>
                    {selectable && <td style={{ padding: pad, width: 44 }} onClick={(e) => e.stopPropagation()}><Checkbox checked={isSel} onChange={() => toggleRow(id)} /></td>}
                    {columns.map((c) => (
                      <td key={c.key} style={{ padding: pad, textAlign: c.align || 'left', fontSize: 14, color: 'var(--f2-text-secondary)', whiteSpace: c.nowrap ? 'nowrap' : 'normal' }}>
                        {c.render ? c.render(r) : r[c.key]}
                      </td>
                    ))}
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
    );
  }

  Object.assign(window.F2, { Avatar, AvatarGroup, List, Timeline, Stat, Progress, Skeleton, EmptyState, CodeBlock, Accordion, DataTable });
})();
