// HACCP TempMon shared React components
// Adapted from HRBR V2.0 components.jsx
const { useState, useEffect, useRef } = React;

// ---------- Icons ----------
function Icon({ name, size = 16 }) {
  const s = size;
  const p = { width: s, height: s, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: 1.6, strokeLinecap: 'round', strokeLinejoin: 'round' };
  switch (name) {
    case 'moon':          return <svg {...p}><path d="M20 15.5A8 8 0 0 1 8.5 4a8 8 0 1 0 11.5 11.5z"/></svg>;
    case 'sun':           return <svg {...p}><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M1 12h2M21 12h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4"/></svg>;
    case 'pulse':         return <svg {...p}><path d="M3 12h3l3-8 4 16 3-8h5"/></svg>;
    case 'trend':         return <svg {...p}><path d="M3 17l6-6 4 4 8-8"/><path d="M14 7h7v7"/></svg>;
    case 'device':        return <svg {...p}><rect x="4" y="6" width="16" height="12" rx="2"/><path d="M8 20v-2M16 20v-2M12 10h.01"/><circle cx="12" cy="14" r="2"/></svg>;
    case 'settings':      return <svg {...p}><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>;
    case 'chevron-right': return <svg {...p}><path d="M9 6l6 6-6 6"/></svg>;
    case 'chevron-down':  return <svg {...p}><path d="M6 9l6 6 6-6"/></svg>;
    case 'activity':      return <svg {...p}><path d="M22 12h-4l-3 9-6-18-3 9H2"/></svg>;
    case 'wifi':          return <svg {...p}><path d="M5 12a10 10 0 0 1 14 0M8.5 15.5a5 5 0 0 1 7 0"/><circle cx="12" cy="19" r="1" fill="currentColor"/></svg>;
    case 'thermometer':   return <svg {...p}><path d="M14 14.76V4a2 2 0 0 0-4 0v10.76a4 4 0 1 0 4 0z"/></svg>;
    case 'alert-triangle':return <svg {...p}><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>;
    case 'check-circle':  return <svg {...p}><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>;
    case 'droplets':      return <svg {...p}><path d="M7 16.3c2.2 0 4-1.83 4-4.05 0-1.16-.57-2.26-1.71-3.19S7.29 6.75 7 5.3c-.29 1.45-1.14 2.84-2.29 3.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"/></svg>;
    case 'battery':       return <svg {...p}><rect x="2" y="7" width="16" height="10" rx="2"/><path d="M22 11v2"/><line x1="6" y1="11" x2="6" y2="13"/></svg>;
    case 'clock':         return <svg {...p}><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>;
    case 'list':          return <svg {...p}><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>;
    case 'history':       return <svg {...p}><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.2"/></svg>;
    case 'zap':           return <svg {...p}><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>;
    case 'refresh':       return <svg {...p}><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/></svg>;
  }
  return null;
}

// ---------- Sparkline ----------
function Sparkline({ data, height = 40, color = 'currentColor', fill = false, strokeWidth = 1.5 }) {
  if (!data || data.length < 2) return <div style={{ height }} />;
  const w = 200;
  const min = Math.min(...data);
  const max = Math.max(...data);
  const range = max - min || 1;
  const step = w / (data.length - 1);
  const points = data.map((v, i) => [i * step, height - ((v - min) / range) * (height - 4) - 2]);
  const path = points.map((p, i) => `${i === 0 ? 'M' : 'L'}${p[0].toFixed(1)} ${p[1].toFixed(1)}`).join(' ');
  const areaPath = path + ` L${w} ${height} L0 ${height} Z`;
  return (
    <svg viewBox={`0 0 ${w} ${height}`} preserveAspectRatio="none" style={{ width: '100%', height }}>
      {fill && <path d={areaPath} fill={color} opacity={0.12} />}
      <path d={path} stroke={color} strokeWidth={strokeWidth} fill="none" strokeLinecap="round" strokeLinejoin="round" vectorEffect="non-scaling-stroke" />
    </svg>
  );
}

// ---------- TempRing ----------
// Circular display for a temperature value, colored by status.
function TempRing({ tempC, status = 'unknown', size = 160, label = 'Probe', unit = '°C' }) {
  const r = size / 2 - 8;
  const c = 2 * Math.PI * r;
  const fill = c * 0.72;
  const color = status === 'safe'   ? 'var(--status-safe)'
              : status === 'breach' ? 'var(--status-breach)'
              : 'var(--line-2)';
  const displayVal = tempC != null ? tempC.toFixed(1) : '--';
  const fontSize = size * 0.28;
  return (
    <div style={{ position: 'relative', width: size, height: size }}>
      <svg width={size} height={size} style={{ transform: 'rotate(-90deg)' }}>
        <circle cx={size/2} cy={size/2} r={r} stroke="var(--line)" strokeWidth={8} fill="none" />
        <circle cx={size/2} cy={size/2} r={r} stroke={color} strokeWidth={8} fill="none"
          strokeDasharray={`${fill} ${c}`} strokeLinecap="round"
          style={{ transition: 'stroke 0.4s ease' }} />
      </svg>
      <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center' }}>
        <div className="num" style={{ fontSize, fontWeight: 600, letterSpacing: '-0.04em', lineHeight: 1 }}>
          {displayVal}
        </div>
        <div className="text-xs text-ink-3" style={{ marginTop: 1, fontSize: size * 0.08 }}>{unit}</div>
        <div className="text-xs text-ink-3" style={{ marginTop: 4, textTransform: 'uppercase', letterSpacing: '0.1em', fontSize: size * 0.075 }}>
          {label}
        </div>
      </div>
    </div>
  );
}

// ---------- Metric ----------
function Metric({ label, value, unit, sub }) {
  return (
    <div className="col gap-4">
      <div className="text-xs text-ink-3" style={{ textTransform: 'uppercase', letterSpacing: '0.1em', fontWeight: 600 }}>{label}</div>
      <div className="row items-baseline gap-4">
        <span className="num" style={{ fontSize: 24, fontWeight: 600, letterSpacing: '-0.02em' }}>{value ?? '--'}</span>
        {unit && <span className="text-sm text-ink-3">{unit}</span>}
      </div>
      {sub && <div className="text-xs text-ink-3">{sub}</div>}
    </div>
  );
}

// ---------- CCP badge ----------
function CcpBadge({ ccpType }) {
  const labels = {
    COLD_CHAIN: 'Cold Chain',
    FREEZER:    'Freezer',
    COOKING:    'Cooking',
    HOT_HOLD:   'Hot Hold',
    AMBIENT:    'Ambient',
  };
  const colors = {
    COLD_CHAIN: 'var(--ccp-cold)',
    FREEZER:    'var(--ccp-freezer)',
    COOKING:    'var(--ccp-cooking)',
    HOT_HOLD:   'var(--ccp-hot-hold)',
    AMBIENT:    'var(--ccp-ambient)',
  };
  if (!ccpType || !labels[ccpType]) return null;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5,
      padding: '4px 10px', borderRadius: 100,
      fontSize: 12, fontWeight: 600, letterSpacing: '0.04em',
      background: colors[ccpType] + '18',
      color: colors[ccpType],
    }}>
      <span style={{ width: 7, height: 7, borderRadius: '50%', background: colors[ccpType], flexShrink: 0 }} />
      {labels[ccpType]}
    </span>
  );
}

// ---------- StatusBadge ----------
function StatusBadge({ status }) {
  const map = {
    safe:    { cls: 'badge-safe',    label: 'IN RANGE' },
    breach:  { cls: 'badge-breach',  label: 'BREACH'   },
    stale:   { cls: 'badge-stale',   label: 'STALE'    },
    unknown: { cls: 'badge-unknown', label: '--'        },
  };
  const { cls, label } = map[status] || map.unknown;
  return <span className={`ccp-badge ${cls}`}>{label}</span>;
}

// ---------- Format helpers ----------
function formatTemp(t)     { return t != null ? t.toFixed(1) + '°C' : '--'; }
function formatBattery(mv) {
  if (mv == null) return '--';
  const pct = Math.max(0, Math.min(100, Math.round((mv - 3300) / (4200 - 3300) * 100)));
  return `${pct}% (${(mv / 1000).toFixed(2)}V)`;
}
function formatUptime(s) {
  if (s == null) return '--';
  const h = Math.floor(s / 3600);
  const m = Math.floor((s % 3600) / 60);
  return h > 0 ? `${h}h ${m}m` : `${m}m`;
}
function formatAge(ts) {
  if (!ts) return '--';
  const s = Math.round((Date.now() - ts) / 1000);
  if (s < 60)  return s + 's ago';
  if (s < 3600) return Math.floor(s / 60) + 'm ago';
  return Math.floor(s / 3600) + 'h ago';
}
function formatTs(ts) {
  if (!ts) return '--';
  return new Date(typeof ts === 'number' && ts < 2e10 ? ts * 1000 : ts)
    .toLocaleString('en-GB', { day: '2-digit', month: 'short', hour: '2-digit', minute: '2-digit', hour12: false });
}

Object.assign(window, {
  Icon, Sparkline, TempRing, Metric, CcpBadge, StatusBadge,
  formatTemp, formatBattery, formatUptime, formatAge, formatTs,
});
