// Shared UI primitives + icon library
const { useState, useEffect, useRef, useMemo, useCallback, createContext, useContext } = React;

// --- Icons (lucide-ish, drawn at 16x16 viewBox 24) ---
const Icon = ({ d, size = 16, stroke = 1.6, fill, children, ...rest }) => (
  <svg viewBox="0 0 24 24" width={size} height={size} fill={fill || "none"} stroke="currentColor"
       strokeWidth={stroke} strokeLinecap="round" strokeLinejoin="round" className="ic" {...rest}>
    {d ? <path d={d} /> : children}
  </svg>
);
const I = {
  home:        (p) => <Icon {...p}><path d="M3 11l9-8 9 8"/><path d="M5 10v10h14V10"/></Icon>,
  play:        (p) => <Icon {...p}><polygon points="6 4 20 12 6 20 6 4" fill="currentColor" stroke="none"/></Icon>,
  bot:         (p) => <Icon {...p}><rect x="4" y="7" width="16" height="13" rx="3"/><path d="M12 3v4"/><circle cx="9" cy="13" r="1.2" fill="currentColor"/><circle cx="15" cy="13" r="1.2" fill="currentColor"/></Icon>,
  key:         (p) => <Icon {...p}><path d="M21 2l-2 2m-7.6 7.6a5 5 0 1 1-5.7 5.7"/><path d="M11.4 11.4L18 5l3 3-3 3"/></Icon>,
  wallet:      (p) => <Icon {...p}><path d="M3 7a2 2 0 0 1 2-2h14v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><path d="M16 12h4"/></Icon>,
  list:        (p) => <Icon {...p}><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="20" y2="18"/></Icon>,
  book:        (p) => <Icon {...p}><path d="M4 4h12a4 4 0 0 1 4 4v12H8a4 4 0 0 1-4-4V4z"/><path d="M4 16h16"/></Icon>,
  users:       (p) => <Icon {...p}><circle cx="9" cy="8" r="3.5"/><path d="M2 20a7 7 0 0 1 14 0"/><circle cx="17" cy="9" r="2.5"/><path d="M22 19a5 5 0 0 0-6-4.5"/></Icon>,
  chart:       (p) => <Icon {...p}><path d="M4 19V5"/><path d="M4 19h16"/><path d="M8 16l3-5 3 3 5-8"/></Icon>,
  cube:        (p) => <Icon {...p}><path d="M12 3l9 5-9 5-9-5 9-5z"/><path d="M3 8v8l9 5 9-5V8"/><path d="M12 13v8"/></Icon>,
  star:        (p) => <Icon {...p}><polygon points="12 2 15 9 22 9 17 14 19 21 12 17 5 21 7 14 2 9 9 9"/></Icon>,
  wrench:      (p) => <Icon {...p}><path d="M14.7 6.3a4 4 0 0 0-5.4 5.4L3 18l3 3 6.3-6.3a4 4 0 0 0 5.4-5.4l-2.4 2.4-2.6-2.6 2.4-2.4z"/></Icon>,
  cog:         (p) => <Icon {...p}><circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M4.2 4.2l2.1 2.1M17.7 17.7l2.1 2.1M2 12h3M19 12h3M4.2 19.8l2.1-2.1M17.7 6.3l2.1-2.1"/></Icon>,
  pulse:       (p) => <Icon {...p}><path d="M3 12h4l3-8 4 16 3-8h4"/></Icon>,
  plus:        (p) => <Icon {...p}><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></Icon>,
  search:      (p) => <Icon {...p}><circle cx="11" cy="11" r="7"/><line x1="20" y1="20" x2="16.6" y2="16.6"/></Icon>,
  filter:      (p) => <Icon {...p}><path d="M3 5h18l-7 9v6l-4-2v-4z"/></Icon>,
  copy:        (p) => <Icon {...p}><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M5 15V5a2 2 0 0 1 2-2h10"/></Icon>,
  trash:       (p) => <Icon {...p}><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6M14 11v6"/></Icon>,
  edit:        (p) => <Icon {...p}><path d="M12 20h9"/><path d="M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4z"/></Icon>,
  check:       (p) => <Icon {...p}><polyline points="20 6 9 17 4 12"/></Icon>,
  x:           (p) => <Icon {...p}><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></Icon>,
  download:    (p) => <Icon {...p}><path d="M12 3v12"/><polyline points="7 10 12 15 17 10"/><path d="M5 21h14"/></Icon>,
  send:        (p) => <Icon {...p}><line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2" stroke="currentColor"/></Icon>,
  sun:         (p) => <Icon {...p}><circle cx="12" cy="12" r="4"/><path d="M12 3v2M12 19v2M5.1 5.1l1.4 1.4M17.5 17.5l1.4 1.4M3 12h2M19 12h2M5.1 18.9l1.4-1.4M17.5 6.5l1.4-1.4"/></Icon>,
  moon:        (p) => <Icon {...p}><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></Icon>,
  flask:       (p) => <Icon {...p}><path d="M9 3h6"/><path d="M10 3v6L4 20a2 2 0 0 0 2 3h12a2 2 0 0 0 2-3l-6-11V3"/></Icon>,
  zap:         (p) => <Icon {...p}><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></Icon>,
  arrowUp:     (p) => <Icon {...p}><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></Icon>,
  arrowDown:   (p) => <Icon {...p}><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></Icon>,
  arrowRight:  (p) => <Icon {...p}><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></Icon>,
  eye:         (p) => <Icon {...p}><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8S1 12 1 12z"/><circle cx="12" cy="12" r="3"/></Icon>,
  eyeOff:      (p) => <Icon {...p}><path d="M17.9 17.9A11.5 11.5 0 0 1 12 20C5 20 1 12 1 12a23 23 0 0 1 5.1-6"/><path d="M22.5 13.8A18 18 0 0 0 23 12s-4-8-11-8a10 10 0 0 0-3.4.6"/><path d="M9.9 9.9a3 3 0 0 0 4.2 4.2"/><line x1="1" y1="1" x2="23" y2="23"/></Icon>,
  more:        (p) => <Icon {...p}><circle cx="5" cy="12" r="1.4" fill="currentColor"/><circle cx="12" cy="12" r="1.4" fill="currentColor"/><circle cx="19" cy="12" r="1.4" fill="currentColor"/></Icon>,
  refresh:     (p) => <Icon {...p}><polyline points="22 12 18 8 22 4"/><path d="M2 12a10 10 0 0 1 18-6"/><polyline points="2 12 6 16 2 20"/><path d="M22 12a10 10 0 0 1-18 6"/></Icon>,
  globe:       (p) => <Icon {...p}><circle cx="12" cy="12" r="9"/><path d="M3 12h18"/><path d="M12 3a14 14 0 0 1 0 18"/><path d="M12 3a14 14 0 0 0 0 18"/></Icon>,
  shield:      (p) => <Icon {...p}><path d="M12 2l8 4v6c0 5-4 9-8 10-4-1-8-5-8-10V6z"/></Icon>,
  spark:       (p) => <Icon {...p}><path d="M12 3v6M12 15v6M3 12h6M15 12h6M5.5 5.5l4 4M14.5 14.5l4 4M5.5 18.5l4-4M14.5 9.5l4-4"/></Icon>,
  link:        (p) => <Icon {...p}><path d="M10 14a5 5 0 0 0 7 0l3-3a5 5 0 0 0-7-7l-1 1"/><path d="M14 10a5 5 0 0 0-7 0l-3 3a5 5 0 0 0 7 7l1-1"/></Icon>,
  file:        (p) => <Icon {...p}><path d="M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><path d="M14 3v6h6"/></Icon>,
  logout:      (p) => <Icon {...p}><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></Icon>,
  menu:        (p) => <Icon {...p}><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></Icon>,
  warn:        (p) => <Icon {...p}><path d="M10.3 3.9L1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/><line x1="12" y1="9" x2="12" y2="13"/><circle cx="12" cy="17" r="0.8" fill="currentColor"/></Icon>,
  code:        (p) => <Icon {...p}><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></Icon>,
  arrowRight:  (p) => <Icon {...p}><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></Icon>,
  alert:       (p) => <Icon {...p}><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></Icon>,
};
window.I = I;
window.Icon = Icon;

// --- Sparkline ---
function Spark({ data, color = "var(--accent)", w = 80, h = 30 }) {
  if (!data || !data.length) return null;
  const min = Math.min(...data), max = Math.max(...data), range = max - min || 1;
  const step = w / (data.length - 1);
  const pts = data.map((v, i) => `${i*step},${h - ((v-min)/range)*h}`).join(" ");
  const area = `M0,${h} L${pts.replaceAll(",", " ").split(" ").map((v, i) => i % 2 ? v : v).join(",")} L${w},${h} Z`;
  return (
    <svg viewBox={`0 0 ${w} ${h}`} width={w} height={h}>
      <polyline fill="none" stroke={color} strokeWidth="1.5" points={pts} strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
}
window.Spark = Spark;

// --- KPI card ---
function KPI({ label, value, unit, delta, spark, sparkColor, icon }) {
  return (
    <div className="kpi">
      <div className="kpi-label">{icon}{label}</div>
      <div className="kpi-value">{value}{unit ? <span className="unit">{unit}</span> : null}</div>
      {(delta != null) && (
        <div className="kpi-foot">
          <span className={"delta " + (delta >= 0 ? "pos" : "neg")}>
            {delta >= 0 ? "+" : ""}{delta}%
          </span>
          <span className="dim">vs last 7d</span>
        </div>
      )}
      {spark && <div className="kpi-spark"><Spark data={spark} color={sparkColor || "var(--accent)"}/></div>}
    </div>
  );
}
window.KPI = KPI;

// --- Modal ---
function Modal({ open, onClose, title, sub, children, foot, size }) {
  useEffect(() => {
    if (!open) return;
    const h = (e) => e.key === "Escape" && onClose();
    document.addEventListener("keydown", h);
    return () => document.removeEventListener("keydown", h);
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div className="modal-back" onClick={onClose}>
      <div className={"modal" + (size ? " " + size : "")} onClick={e => e.stopPropagation()}>
        <div className="modal-head">
          <div style={{flex: 1}}>
            <h3>{title}</h3>
            {sub && <div className="sub">{sub}</div>}
          </div>
          <button className="icon-btn" onClick={onClose}><I.x/></button>
        </div>
        <div className="modal-body">{children}</div>
        {foot && <div className="modal-foot">{foot}</div>}
      </div>
    </div>
  );
}
window.Modal = Modal;

// --- Toasts ---
const ToastCtx = createContext(null);
function ToastProvider({ children }) {
  const [items, setItems] = useState([]);
  const push = useCallback((msg, kind = "info") => {
    const id = Math.random();
    setItems(s => [...s, { id, msg, kind }]);
    setTimeout(() => setItems(s => s.filter(x => x.id !== id)), 3000);
  }, []);
  return (
    <ToastCtx.Provider value={push}>
      {children}
      <div className="toast-stack">
        {items.map(t => (
          <div key={t.id} className={"toast " + t.kind}>
            {t.kind === "pos" ? <I.check stroke={2.4}/> : t.kind === "neg" ? <I.warn/> : <I.spark/>}
            <span>{t.msg}</span>
          </div>
        ))}
      </div>
    </ToastCtx.Provider>
  );
}
function useToast() { return useContext(ToastCtx); }
window.ToastProvider = ToastProvider;
window.useToast = useToast;

// --- Switch ---
function Switch({ on, onChange }) {
  return <div className={"switch" + (on ? " on" : "")} onClick={() => onChange(!on)} role="switch" aria-checked={on}/>;
}
window.Switch = Switch;

// --- Provider chip ---
function ProvChip({ slug }) {
  const p = window.HDR_DATA.providers[slug] || { name: slug, color: "#888" };
  return <span className="prov-chip"><span className="pd" style={{ background: p.color }}/>{p.name}</span>;
}
window.ProvChip = ProvChip;

// --- Tabs ---
function Tabs({ items, value, onChange }) {
  return (
    <div className="tabs">
      {items.map(it => (
        <button key={it.value} className={"tab" + (value === it.value ? " active" : "")}
                onClick={() => onChange(it.value)}>
          {it.icon}{it.label}
          {it.count != null && <span className="badge">{it.count}</span>}
        </button>
      ))}
    </div>
  );
}
window.Tabs = Tabs;

// --- Bar chart (simple SVG) ---
function BarChart({ data, height = 200, fmt = v => v, color = "var(--accent)" }) {
  const max = Math.max(...data.map(d => d.v), 1);
  const w = 100 / data.length;
  return (
    <div style={{ position: "relative" }}>
      <svg viewBox={`0 0 100 ${height}`} preserveAspectRatio="none" style={{ width: "100%", height, display: "block" }}>
        {[0.25, 0.5, 0.75].map(p => (
          <line key={p} x1="0" x2="100" y1={height*p} y2={height*p} stroke="var(--grid-line)" strokeWidth="0.5"/>
        ))}
        {data.map((d, i) => {
          const h = (d.v / max) * (height - 16);
          return (
            <rect key={i}
              x={i*w + w*0.18} y={height - h - 2}
              width={w*0.64} height={h}
              fill={color} rx="0.6" opacity={d.muted ? 0.4 : 1}>
              <title>{d.label}: {fmt(d.v)}</title>
            </rect>
          );
        })}
      </svg>
      <div style={{ display: "flex", justifyContent: "space-between", marginTop: 8, fontSize: 11, color: "var(--text-dim)", fontFamily: "var(--font-mono)" }}>
        {data.filter((_, i) => i % Math.ceil(data.length/6) === 0).map((d, i) => <span key={i}>{d.label}</span>)}
      </div>
    </div>
  );
}
window.BarChart = BarChart;

// --- Line chart with area ---
function LineChart({ series, height = 220, color = "var(--accent)", fmt = v => v }) {
  if (!series || !series.length) return null;
  const vals = series.map(s => s.v);
  const max = Math.max(...vals), min = Math.min(...vals, 0);
  const range = max - min || 1;
  const W = 100, H = height;
  const step = W / (series.length - 1);
  const pts = series.map((s, i) => [i*step, H - 20 - ((s.v - min)/range)*(H - 40)]);
  const path = pts.map((p,i) => (i ? "L" : "M") + p[0] + " " + p[1]).join(" ");
  const area = path + ` L${W} ${H-20} L0 ${H-20} Z`;
  return (
    <div style={{position: "relative"}}>
      <svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" style={{ width: "100%", height, display: "block" }}>
        <defs>
          <linearGradient id="lc-grad" x1="0" x2="0" y1="0" y2="1">
            <stop offset="0%" stopColor={color} stopOpacity="0.25"/>
            <stop offset="100%" stopColor={color} stopOpacity="0"/>
          </linearGradient>
        </defs>
        {[0.25,0.5,0.75].map(p => (
          <line key={p} x1="0" x2={W} y1={H-20-(H-40)*p} y2={H-20-(H-40)*p} stroke="var(--grid-line)" strokeWidth="0.4"/>
        ))}
        <path d={area} fill="url(#lc-grad)"/>
        <path d={path} fill="none" stroke={color} strokeWidth="1" vectorEffect="non-scaling-stroke"/>
      </svg>
      <div style={{ display: "flex", justifyContent: "space-between", marginTop: 4, fontSize: 11, color: "var(--text-dim)", fontFamily: "var(--font-mono)" }}>
        {series.filter((_, i) => i % Math.ceil(series.length/6) === 0).map((s, i) => <span key={i}>{s.label}</span>)}
      </div>
    </div>
  );
}
window.LineChart = LineChart;

// --- Donut chart ---
function Donut({ slices, size = 140, thickness = 18 }) {
  const total = slices.reduce((a, s) => a + s.v, 0) || 1;
  const r = (size - thickness) / 2;
  const c = 2 * Math.PI * r;
  let off = 0;
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
      <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="var(--surface-3)" strokeWidth={thickness}/>
      {slices.map((s, i) => {
        const len = (s.v / total) * c;
        const el = (
          <circle key={i} cx={size/2} cy={size/2} r={r} fill="none"
                  stroke={s.color} strokeWidth={thickness}
                  strokeDasharray={`${len} ${c - len}`}
                  strokeDashoffset={-off}
                  transform={`rotate(-90 ${size/2} ${size/2})`}
                  strokeLinecap="butt"/>
        );
        off += len;
        return el;
      })}
    </svg>
  );
}
window.Donut = Donut;

// Copy to clipboard helper
window.copyText = (txt, toast) => {
  navigator.clipboard?.writeText(txt).then(() => toast && toast("Copied to clipboard", "pos"));
};
