// Visual primitives. Pure presentational. Consumers pass data + handlers.
// NOTE: each web/admin/*.jsx file is loaded as a separate
// `<script type="text/babel">` in the same global scope. Top-level
// `const { useEffect } = React` would collide across files; we use
// `React.useEffect` etc. directly to avoid that.

function Icon({ name, size = 14, color }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (ref.current && window.lucide) {
      ref.current.innerHTML = '';
      const el = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
      el.setAttribute('data-lucide', name);
      el.setAttribute('width', size);
      el.setAttribute('height', size);
      el.style.display = 'block';
      ref.current.appendChild(el);
      window.lucide.createIcons({ root: ref.current });
    }
  }, [name, size]);
  return <span ref={ref} className="icon" style={{ display: 'inline-flex', color: color || 'currentColor' }} />;
}
window.Icon = Icon;

function Card({ title, value, foot, children, accent }) {
  return (
    <div className="card">
      {title && <div className="card-head"><span>{title}</span>{accent && <span>{accent}</span>}</div>}
      {value !== undefined && <div className="card-value">{value}</div>}
      {children}
      {foot && <div className="card-foot">{foot}</div>}
    </div>
  );
}
window.Card = Card;

// SVG sparkline. Auto-scales to its container width via ResizeObserver.
function Sparkline({ data, height = 36, color = '#60A5FA', area = true }) {
  const ref = React.useRef(null);
  const [w, setW] = React.useState(120);
  React.useEffect(() => {
    if (!ref.current) return;
    const ro = new ResizeObserver((es) => {
      for (const e of es) setW(Math.max(40, Math.floor(e.contentRect.width)));
    });
    ro.observe(ref.current);
    return () => ro.disconnect();
  }, []);
  const pts = data || [];
  const max = pts.length ? Math.max(1, ...pts.map((p) => p.count)) : 1;
  const path = pts.map((p, i) => {
    const x = (i / Math.max(1, pts.length - 1)) * (w - 4) + 2;
    const y = height - 2 - (p.count / max) * (height - 6);
    return (i === 0 ? 'M' : 'L') + x.toFixed(1) + ' ' + y.toFixed(1);
  }).join(' ');
  const areaPath = pts.length ? path + ' L ' + (w - 2).toFixed(1) + ' ' + (height - 2) + ' L 2 ' + (height - 2) + ' Z' : '';
  return (
    <div ref={ref} className="spark" style={{ height }}>
      <svg width={w} height={height} viewBox={`0 0 ${w} ${height}`}>
        {area && <path d={areaPath} fill={color} fillOpacity="0.18" />}
        <path d={path} fill="none" stroke={color} strokeWidth="1.5" strokeLinejoin="round" strokeLinecap="round" />
      </svg>
    </div>
  );
}
window.Sparkline = Sparkline;

// Horizontal bar chart from {label,count}[].
function BarList({ rows, max, color }) {
  const m = max || rows.reduce((a, r) => Math.max(a, r.count), 1);
  return (
    <div>
      {rows.map((r, i) => (
        <div key={i} className="bar-row">
          <div className="lbl" title={r.label}>{r.label}</div>
          <div className="bg-bar"><div className="bar" style={{ width: ((r.count / m) * 100).toFixed(1) + '%', background: color }} /></div>
          <div className="num">{F.num(r.count)}</div>
        </div>
      ))}
    </div>
  );
}
window.BarList = BarList;

// 7×N day heatmap; cells colored by quartile.
function Heatmap({ data, max }) {
  const m = max || data.reduce((a, r) => Math.max(a, r.count), 1);
  const lvl = (n) => {
    if (n <= 0) return 0;
    const r = n / m;
    if (r < 0.25) return 1;
    if (r < 0.5) return 2;
    if (r < 0.75) return 3;
    return 4;
  };
  return (
    <div className="heatmap">
      {data.map((d, i) => (
        <div key={i} className={'cell l' + lvl(d.count)} title={d.date + ' · ' + d.count} />
      ))}
    </div>
  );
}
window.Heatmap = Heatmap;

function Toast({ kind, children }) {
  return <div className={'toast ' + (kind || 'ok')}>{children}</div>;
}
window.Toast = Toast;

function Spinner() { return <span className="spinner" />; }
window.Spinner = Spinner;

function Badge({ kind, children }) { return <span className={'badge ' + (kind || '')}>{children}</span>; }
window.Badge = Badge;

function VerifiedPill({ verified }) {
  return verified
    ? <Badge kind="ok"><Icon name="check" size={11} /> verificado</Badge>
    : <Badge kind="warn">sin verificar</Badge>;
}
window.VerifiedPill = VerifiedPill;

function McpPill({ on, lastUsedAt }) {
  if (!on) return <Badge>sin MCP</Badge>;
  return <Badge kind="info"><Icon name="zap" size={11} /> MCP{lastUsedAt ? ' · ' + F.ago(lastUsedAt) : ''}</Badge>;
}
window.McpPill = McpPill;

function SearchBar({ value, onChange, placeholder }) {
  return (
    <div className="row" style={{ gap: 8, flex: 1 }}>
      <div style={{ position: 'relative', flex: 1 }}>
        <span style={{ position: 'absolute', left: 10, top: 8, color: 'var(--text-dim)' }}><Icon name="search" size={14} /></span>
        <input className="input" style={{ paddingLeft: 32 }}
          placeholder={placeholder || 'Buscar…'}
          value={value || ''} onChange={(e) => onChange(e.target.value)} />
      </div>
    </div>
  );
}
window.SearchBar = SearchBar;

function Drawer({ onClose, children, title }) {
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [onClose]);
  return (
    <div className="overlay" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="drawer">
        <div className="drawer-head">
          <h3>{title}</h3>
          <button className="btn ghost" onClick={onClose}><Icon name="x" size={14} /></button>
        </div>
        {children}
      </div>
    </div>
  );
}
window.Drawer = Drawer;
