/* ============================================================
   SHARED UI — icons, chips, live values, gauge, sparkline, KPI
   ============================================================ */

/* ---- App context (shared across files) ---------------------- */
window.AppCtx = React.createContext(null);
function useApp() { return React.useContext(window.AppCtx); }

/* ---- Icon set (lucide-style inline) ------------------------- */
const ICONS = {
  dashboard:'<rect width="7" height="9" x="3" y="3" rx="1"/><rect width="7" height="5" x="14" y="3" rx="1"/><rect width="7" height="9" x="14" y="12" rx="1"/><rect width="7" height="5" x="3" y="16" rx="1"/>',
  factory:'<path d="M2 20a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8l-7 5V8l-7 5V5a1 1 0 0 0-1-1H4a2 2 0 0 0-2 2Z"/><path d="M17 18h1"/><path d="M12 18h1"/><path d="M7 18h1"/>',
  inbox:'<polyline points="22 12 16 12 14 15 10 15 8 12 2 12"/><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z"/>',
  tunnel:'<rect x="3" y="6" width="18" height="13" rx="2"/><path d="M3 11h18"/><path d="M8 19v-4"/><path d="M16 19v-4"/>',
  droplets:'<path d="M7 16.3c2.2 0 4-1.83 4-4.05 0-1.16-.57-2.26-1.71-3.19S7.29 4.7 7 2.3c-.29 2.4-1.15 3.83-2.29 4.76S3 11.1 3 12.25c0 2.22 1.8 4.05 4 4.05z"/><path d="M12.56 6.6A10.97 10.97 0 0 0 14 3.02c.5 2.5 2 4.9 4 6.5s3 3.5 3 5.5a6.98 6.98 0 0 1-11.91 4.97"/>',
  flame:'<path d="M8.5 14.5A2.5 2.5 0 0 0 11 12c0-1.38-.5-2-1-3-1.072-2.143-.224-4.054 2-6 .5 2.5 2 4.9 4 6.5 2 1.6 3 3.5 3 5.5a7 7 0 1 1-14 0c0-1.153.433-2.294 1-3a2.5 2.5 0 0 0 2.5 2.5z"/>',
  zap:'<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>',
  thermo:'<path d="M14 4v10.54a4 4 0 1 1-4 0V4a2 2 0 0 1 4 0Z"/>',
  wind:'<path d="M12.8 19.6A2 2 0 1 0 14 16H2"/><path d="M17.5 8a2.5 2.5 0 1 1 2 4H2"/><path d="M9.8 4.4A2 2 0 1 1 11 8H2"/>',
  filter:'<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/>',
  gauge:'<path d="m12 14 4-4"/><path d="M3.34 19a10 10 0 1 1 17.32 0"/>',
  bell:'<path d="M10.268 21a2 2 0 0 0 3.464 0"/><path d="M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326"/>',
  chart:'<path d="M3 3v16a2 2 0 0 0 2 2h16"/><path d="m19 9-5 5-4-4-3 3"/>',
  activity:'<path d="M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2"/>',
  cpu:'<rect width="16" height="16" x="4" y="4" rx="2"/><rect width="6" height="6" x="9" y="9" rx="1"/><path d="M15 2v2"/><path d="M15 20v2"/><path d="M2 15h2"/><path d="M2 9h2"/><path d="M20 15h2"/><path d="M20 9h2"/><path d="M9 2v2"/><path d="M9 20v2"/>',
  sliders:'<line x1="4" x2="4" y1="21" y2="14"/><line x1="4" x2="4" y1="10" y2="3"/><line x1="12" x2="12" y1="21" y2="12"/><line x1="12" x2="12" y1="8" y2="3"/><line x1="20" x2="20" y1="21" y2="16"/><line x1="20" x2="20" y1="12" y2="3"/><line x1="2" x2="6" y1="14" y2="14"/><line x1="10" x2="14" y1="8" y2="8"/><line x1="18" x2="22" y1="16" y2="16"/>',
  x:'<path d="M18 6 6 18"/><path d="m6 6 12 12"/>',
  chevR:'<path d="m9 18 6-6-6-6"/>',
  chevD:'<path d="m6 9 6 6 6-6"/>',
  search:'<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>',
  user:'<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>',
  wifi:'<path d="M12 20h.01"/><path d="M2 8.82a15 15 0 0 1 20 0"/><path d="M5 12.859a10 10 0 0 1 14 0"/><path d="M8.5 16.429a5 5 0 0 1 7 0"/>',
  power:'<path d="M12 2v10"/><path d="M18.4 6.6a9 9 0 1 1-12.77.04"/>',
  play:'<polygon points="6 3 20 12 6 21 6 3"/>',
  stop:'<rect width="14" height="14" x="5" y="5" rx="2"/>',
  alert:'<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/>',
  check:'<path d="M20 6 9 17l-5-5"/>',
  checkc:'<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><path d="m9 11 3 3L22 4"/>',
  lock:'<rect width="18" height="11" x="3" y="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>',
  unlock:'<rect width="18" height="11" x="3" y="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 9.9-1"/>',
  database:'<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5V19A9 3 0 0 0 21 19V5"/><path d="M3 12A9 3 0 0 0 21 12"/>',
  refresh:'<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M8 16H3v5"/>',
  dot:'<circle cx="12" cy="12" r="4"/>',
  gas:'<path d="M9 2h6"/><path d="M12 2v6"/><circle cx="12" cy="14" r="8"/>',
  valve:'<path d="M3 12h4l5-4v8l-5-4"/><path d="M21 12h-4l-5-4v8l5-4"/><path d="M12 8V4"/><circle cx="12" cy="3" r="1"/>',
  pump:'<circle cx="12" cy="12" r="8"/><path d="M12 4v8l5-3"/><path d="M4 12h4"/>',
  motor:'<rect x="2" y="7" width="14" height="10" rx="2"/><path d="M16 10h3l3 2-3 2h-3"/><path d="M5 7V5"/><path d="M11 7V5"/>',
  fan:'<path d="M10.827 16.379a6.082 6.082 0 0 1-8.618-7.002l5.412 1.45a6.082 6.082 0 0 1 7.002-8.618l-1.45 5.412a6.082 6.082 0 0 1 8.618 7.002l-5.412-1.45a6.082 6.082 0 0 1-7.002 8.618l1.45-5.412Z"/><circle cx="12" cy="12" r="2"/>',
  maximize:'<path d="M8 3H5a2 2 0 0 0-2 2v3"/><path d="M21 8V5a2 2 0 0 0-2-2h-3"/><path d="M3 16v3a2 2 0 0 0 2 2h3"/><path d="M16 21h3a2 2 0 0 0 2-2v-3"/>',
  download:'<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" x2="12" y1="15" y2="3"/>',
  beaker:'<path d="M4.5 3h15"/><path d="M6 3v16a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V3"/><path d="M6 14h12"/>',
  battery:'<rect width="16" height="10" x="2" y="7" rx="2"/><line x1="22" x2="22" y1="11" y2="13"/><path d="M6 11v2"/><path d="M10 11v2"/>',
  leaf:'<path d="M11 20A7 7 0 0 1 9.8 6.1C15.5 5 17 4.48 19 2c1 2 2 4.18 2 8 0 5.5-4.78 10-10 10Z"/><path d="M2 21c0-3 1.85-5.36 5.08-6"/>',
  settings:'<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/>',
};
function Icon({ n, size = 18, sw = 1.9, style, cls }) {
  return React.createElement("svg", {
    width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor",
    strokeWidth: sw, strokeLinecap: "round", strokeLinejoin: "round", className: cls, style,
    dangerouslySetInnerHTML: { __html: ICONS[n] || ICONS.dot },
  });
}

/* ---- status helpers ---------------------------------------- */
function StatusChip({ kind, label }) {
  return <span className={"chip " + kind}><span className="d"></span>{label}</span>;
}
// derive a status kind + label key from any device
function deviceStatus(d, t) {
  if (d.kind === "valve") {
    if (d.fault) return { k: "alarm", l: t("st_fault") };
    if (d.travelling) return { k: "warn", l: t("st_travelling") };
    return d.open ? { k: "run", l: t("st_open") } : { k: "idle", l: t("st_closed") };
  }
  if (d.kind === "motor") {
    if (d.fault) return { k: "alarm", l: t("st_fault") };
    return d.running ? { k: "run", l: t("st_running") } : { k: "idle", l: t("st_stopped") };
  }
  if (d.kind === "instrument") {
    const q = window.qualOf(d);
    if (q === "alarm") return { k: "alarm", l: t("st_alarm") };
    if (q === "warn") return { k: "warn", l: t("st_warn") };
    return { k: "run", l: t("st_ok") };
  }
  return { k: "idle", l: "—" };
}

/* ---- live numeric value (mono pill) ------------------------ */
function LiveValue({ d, big }) {
  const q = window.qualOf(d);
  const cls = q === "alarm" ? "lv al" : q === "warn" ? "lv hi" : "lv";
  return (
    <span className={cls} style={big ? { padding: "4px 10px" } : null}>
      <span className="n" style={big ? { fontSize: 16 } : null}>{fmtNum(d.v, d.fmt)}</span>
      <span className="u">{d.unit}</span>
    </span>
  );
}

/* ---- sparkline from rolling history ------------------------ */
function Sparkline({ id, w = 200, h = 30, color = "#6E97C4", fill = true }) {
  const hist = (window.HIST && window.HIST[id]) || [];
  if (hist.length < 2) return <svg width={w} height={h}></svg>;
  const mn = Math.min(...hist), mx = Math.max(...hist), rng = (mx - mn) || 1;
  const step = w / (hist.length - 1);
  const pts = hist.map((v, i) => [i * step, h - 3 - ((v - mn) / rng) * (h - 6)]);
  const dLine = pts.map((p, i) => (i ? "L" : "M") + p[0].toFixed(1) + " " + p[1].toFixed(1)).join(" ");
  const dArea = dLine + ` L ${w} ${h} L 0 ${h} Z`;
  const gid = "sg" + id;
  return (
    <svg width={w} height={h} style={{ display: "block" }}>
      {fill && <defs><linearGradient id={gid} x1="0" y1="0" x2="0" y2="1">
        <stop offset="0" stopColor={color} stopOpacity="0.35" /><stop offset="1" stopColor={color} stopOpacity="0" />
      </linearGradient></defs>}
      {fill && <path d={dArea} fill={`url(#${gid})`} />}
      <path d={dLine} fill="none" stroke={color} strokeWidth="1.6" strokeLinejoin="round" />
    </svg>
  );
}

/* ---- radial gauge ------------------------------------------ */
function Gauge({ value, min, max, unit, label, size = 132, warnAt, alarmAt, dp = 0 }) {
  const pct = Math.max(0, Math.min(1, (value - min) / (max - min)));
  const a0 = -220, a1 = 40, ang = a0 + (a1 - a0) * pct;
  const r = size / 2 - 12, cx = size / 2, cy = size / 2;
  const pol = (a) => [cx + r * Math.cos(a * Math.PI / 180), cy + r * Math.sin(a * Math.PI / 180)];
  const arc = (s, e) => { const [x0, y0] = pol(s), [x1, y1] = pol(e); const large = (e - s) > 180 ? 1 : 0; return `M ${x0} ${y0} A ${r} ${r} 0 ${large} 1 ${x1} ${y1}`; };
  let col = "#3D8BE0";
  if (alarmAt != null && value >= alarmAt) col = "#f08478"; else if (warnAt != null && value >= warnAt) col = "#f3c45a";
  const [nx, ny] = pol(ang);
  return (
    <div className="gauge-wrap" style={{ flexDirection: "column", gap: 4 }}>
      <svg width={size} height={size * 0.82} viewBox={`0 0 ${size} ${size * 0.82}`}>
        <path d={arc(a0, a1)} stroke="#15294a" strokeWidth="9" fill="none" strokeLinecap="round" />
        <path d={arc(a0, ang)} stroke={col} strokeWidth="9" fill="none" strokeLinecap="round" />
        <line x1={cx} y1={cy} x2={nx} y2={ny} stroke={col} strokeWidth="2.5" strokeLinecap="round" />
        <circle cx={cx} cy={cy} r="4" fill={col} />
        <text x={cx} y={cy - 16} textAnchor="middle" fill="#fff" style={{ font: "700 22px var(--font-mono)" }}>{fmtNum(value, dp)}</text>
        <text x={cx} y={cy} textAnchor="middle" fill="#647a98" style={{ font: "600 10px var(--font-mono)" }}>{unit}</text>
      </svg>
      {label && <div style={{ fontSize: 11, color: "var(--hud-text-2)", textAlign: "center", maxWidth: size + 20 }}>{label}</div>}
    </div>
  );
}

/* ---- KPI card ---------------------------------------------- */
function KPI({ icon, label, value, unit, dp, sub, accent, sparkId, color }) {
  return (
    <div className={"kpi" + (accent ? " accent" : "")}>
      <div className="k-l">{icon && <Icon n={icon} size={13} />}{label}</div>
      <div className="k-v">{typeof value === "number" ? fmtNum(value, dp) : value}{unit && <span className="u">{unit}</span>}</div>
      {sub && <div className="k-d">{sub}</div>}
      {sparkId && <div className="k-spark"><Sparkline id={sparkId} w={260} h={30} color={color || "#3D8BE0"} /></div>}
    </div>
  );
}

Object.assign(window, { useApp, Icon, StatusChip, deviceStatus, LiveValue, Sparkline, Gauge, KPI });
