// Schaffner OS — shared UI primitives
const { useState, useEffect, useMemo } = React;

function fmtMoney(n) {
  return '$' + Math.round(n).toLocaleString('en-US');
}
function fmtK(n) {
  return n >= 1000 ? '$' + (n / 1000).toFixed(1).replace(/\.0$/, '') + 'k' : fmtMoney(n);
}
function pct(x, d = 1) { return (x * 100).toFixed(d) + '%'; }

function Delta({ value }) {
  const up = value >= 0;
  return (
    <span className={'delta ' + (up ? 'up' : 'down')}>
      {up ? '▲' : '▼'} {Math.abs(value).toFixed(1)}%
    </span>
  );
}

// Simple sparkline — pure data viz
function Spark({ data, color = 'var(--moss)', w = 120, h = 34, fill = true }) {
  const min = Math.min(...data), max = Math.max(...data);
  const range = max - min || 1;
  const pts = data.map((v, i) => [
    (i / (data.length - 1)) * (w - 2) + 1,
    h - 3 - ((v - min) / range) * (h - 6),
  ]);
  const line = pts.map(p => p.join(',')).join(' ');
  const area = `1,${h} ` + line + ` ${w - 1},${h}`;
  return (
    <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`} aria-hidden="true">
      {fill ? <polygon points={area} fill={color} opacity="0.1"></polygon> : null}
      <polyline points={line} fill="none" stroke={color} strokeWidth="1.6" strokeLinejoin="round" strokeLinecap="round"></polyline>
      <circle cx={pts[pts.length - 1][0]} cy={pts[pts.length - 1][1]} r="2.4" fill={color}></circle>
    </svg>
  );
}

// Multi-series line chart for revenue trend.
// fmt(v) optionally formats axis + end labels (default money: "$<v>k").
// A series may set { dash: true } for a dashed trend line and name '' to skip its label.
function TrendChart({ series, labels, height = 190, fmt }) {
  const w = 760, h = height, padL = 44, padR = 96, padT = 14, padB = 24;
  const axisFmt = fmt || (v => '$' + Math.round(v) + 'k');
  const labelFmt = fmt || (v => '$' + v + 'k');
  const all = series.flatMap(s => s.data);
  const lo = Math.min(...all), hi = Math.max(...all);
  const min = lo > 0 ? lo * 0.96 : lo, max = hi * 1.03;
  const x = i => padL + (i / (series[0].data.length - 1)) * (w - padL - padR);
  const y = v => padT + (1 - (v - min) / (max - min)) * (h - padT - padB);
  const gridVals = [min, (min + max) / 2, max];
  return (
    <svg width="100%" viewBox={`0 0 ${w} ${h}`} style={{ display: 'block' }} aria-hidden="true">
      {gridVals.map((g, i) => (
        <g key={i}>
          <line x1={padL} x2={w - padR} y1={y(g)} y2={y(g)} stroke="var(--line-2)" strokeWidth="1"></line>
          <text x={padL - 8} y={y(g) + 3.5} textAnchor="end" fontSize="10" fontFamily="var(--mono)" fill="var(--ink-3)">
            {axisFmt(g)}
          </text>
        </g>
      ))}
      {labels.map((lb, i) => lb ? (
        <text key={i} x={x(i)} y={h - 6} textAnchor="middle" fontSize="10" fontFamily="var(--mono)" fill="var(--ink-3)">{lb}</text>
      ) : null)}
      {series.map((s, si) => {
        const pts = s.data.map((v, i) => `${x(i)},${y(v)}`).join(' ');
        const last = s.data[s.data.length - 1];
        return (
          <g key={si}>
            <polyline points={pts} fill="none" stroke={s.color} strokeWidth={s.bold ? 2.2 : 1.6}
              strokeDasharray={s.dash ? '5 5' : undefined}
              strokeLinejoin="round" strokeLinecap="round" opacity={s.dash ? 0.7 : (s.bold ? 1 : 0.85)}></polyline>
            {s.dash ? null : <circle cx={x(s.data.length - 1)} cy={y(last)} r="2.6" fill={s.color}></circle>}
            {s.name ? (
              <text x={x(s.data.length - 1) + 8} y={y(last) + 3.5} fontSize="10.5" fontWeight="600"
                fontFamily="var(--sans)" fill={s.color}>{s.name} · {labelFmt(last)}</text>
            ) : null}
          </g>
        );
      })}
    </svg>
  );
}

function SectionHead({ title, action, onAction }) {
  return (
    <div className="sect">
      <h2>{title}</h2>
      <span className="rule"></span>
      {action ? <button className="more" onClick={onAction}>{action}</button> : null}
    </div>
  );
}

function StatusBadge({ status }) {
  const map = {
    ok: ['ok', 'In stock'], low: ['warn', 'Low'], reorder: ['bad', 'Reorder now'], watch: ['neutral', 'Count due'],
  };
  const [tone, label] = map[status] || ['neutral', status];
  return <span className={'badge ' + tone}>{label}</span>;
}

function Toast({ msg }) {
  if (!msg) return null;
  return <div className="toast">{msg}</div>;
}

function useToast() {
  const [msg, setMsg] = useState(null);
  const show = (m) => {
    setMsg(m);
    window.clearTimeout(show._t);
    show._t = window.setTimeout(() => setMsg(null), 2200);
  };
  return [msg, show];
}

Object.assign(window, {
  fmtMoney, fmtK, pct, Delta, Spark, TrendChart, SectionHead, StatusBadge, Toast, useToast,
});
