// Telemetría en tiempo real — WellData-style DEPTH-INDEXED track viewer.
// - Depth runs top→bottom on Y axis
// - Each track renders 2–3 overlapping channels horizontally (area + line)
// - Time axis on far-left column
// - Readout cards below each track; toolface + summary on the right

function TelemetriaModule() {
  const [hasSensor, setHasSensor] = useState(true);
  const [mode, setMode] = useState('time'); // 'time' | 'depth'
  const [running, setRunning] = useState(true);
  const [hoverY, setHoverY] = useState(null); // 0..1 (row in depth)

  // Generate depth-indexed samples. One sample every 0.5 m of depth.
  // In real WellData the Y axis is time or depth; we use depth for this view.
  const N = 260; // 260 rows * 0.5m = 130m window
  const startDepth = 10024.2;
  const [samples, setSamples] = useState(() => makeDepthSeries(N, startDepth));

  useEffect(() => {
    if (!running || !hasSensor) return;
    const iv = setInterval(() => setSamples((prev) => advanceDepthSeries(prev)), 1100);
    return () => clearInterval(iv);
  }, [running, hasSensor]);

  if (!hasSensor) {
    return <SensorNotEnabled onEnable={() => setHasSensor(true)} />;
  }

  const latest = samples[samples.length - 1];

  return (
    <div className="view-in absolute inset-0 flex flex-col bg-[#0A0E14] text-slate-100">
      <TelemetryStatusBar
        latest={latest}
        mode={mode}
        setMode={setMode}
        running={running}
        setRunning={setRunning}
      />

      <div className="flex-1 min-h-0 flex">
        {/* Time/depth column */}
        <TimeColumn samples={samples} mode={mode} hoverY={hoverY} />

        {/* Main tracks area */}
        <div className="flex-1 min-w-0 flex flex-col">
          <TracksGrid samples={samples} hoverY={hoverY} onHoverY={setHoverY} latest={latest} />
        </div>

        {/* Right summary column */}
        <RightSummary latest={latest} />
      </div>
    </div>
  );
}

// ============================================================================
// Status bar / toolbar
// ============================================================================
function TelemetryStatusBar({ latest, mode, setMode, running, setRunning }) {
  return (
    <>
      {/* top header row (breadcrumb-ish) */}
      <div className="border-b border-slate-800/80 bg-[#0D1218] px-4 py-2 flex items-center flex-wrap gap-x-5 gap-y-1.5 text-[11.5px] shrink-0">
        <div className="flex items-center gap-1.5">
          <span className="text-slate-500 uppercase text-[10px] tracking-wider">Total depth</span>
          <span className="text-white font-semibold tnum mono">
            {latest.holeDepth.toFixed(2)} m
          </span>
        </div>
        <div className="flex items-center gap-1.5">
          <span className="text-slate-500 uppercase text-[10px] tracking-wider">Bit position</span>
          <span className="text-white font-semibold tnum mono">{latest.bitDepth.toFixed(2)} m</span>
        </div>
        <div className="flex items-center gap-1.5">
          <span className="text-slate-500 uppercase text-[10px] tracking-wider">Rig activity</span>
          <span className="text-white font-semibold">Rotary Drilling</span>
        </div>
        <div className="flex items-center gap-1.5">
          <span className="text-slate-500 uppercase text-[10px] tracking-wider">WOB target</span>
          <span className="text-white font-semibold mono">General</span>
        </div>
        <div className="ml-auto flex items-center gap-3">
          <span className="relative flex h-2 w-2">
            <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald opacity-75" />
            <span className="relative inline-flex rounded-full h-2 w-2 bg-emerald" />
          </span>
          <span className="text-emerald font-semibold uppercase tracking-wider text-[10px]">
            LIVE
          </span>
          <span className="text-slate-500 mono text-[10.5px]">mar 22:43:06</span>
        </div>
      </div>

      {/* mode toggle row */}
      <div className="border-b border-slate-800/80 bg-[#0D1218] px-4 py-1.5 flex items-center gap-2 shrink-0">
        <div className="inline-flex bg-[#0A0E14] border border-slate-800 rounded p-0.5">
          {[
            ['time', 'Time'],
            ['depth', 'Depth'],
          ].map(([k, l]) => (
            <button
              key={k}
              onClick={() => setMode(k)}
              className={cn(
                'px-3 h-7 rounded text-[11px] font-semibold uppercase tracking-wider transition',
                mode === k ? 'bg-[#E8A21C] text-[#0A0E14]' : 'text-slate-400 hover:text-white',
              )}
            >
              {l}
            </button>
          ))}
        </div>
        <div className="text-[10.5px] text-slate-500 mono ml-3 hidden sm:block">
          {mode === 'time' ? 'Feb 11 – Feb 14' : '9894 – 10024 m'}
        </div>
        <button
          onClick={() => setRunning((r) => !r)}
          className="ml-auto h-7 px-2.5 rounded-md border border-slate-800 bg-[#151A22] hover:bg-[#1A212C] text-[11px] text-slate-200 inline-flex items-center gap-1.5"
        >
          <Icon name={running ? 'pause' : 'play'} size={11} /> {running ? 'Pausar' : 'Reanudar'}
        </button>
        <button className="h-7 px-2.5 rounded-md border border-slate-800 bg-[#151A22] hover:bg-[#1A212C] text-[11px] text-slate-200 inline-flex items-center gap-1.5">
          <Icon name="download" size={11} /> CSV
        </button>
        <button className="h-7 w-7 rounded-md border border-slate-800 bg-[#151A22] hover:bg-[#1A212C] text-slate-300 inline-flex items-center justify-center">
          <Icon name="settings" size={12} />
        </button>
      </div>
    </>
  );
}
// ============================================================================
// Left time column (with depth labels + connection markers)
// ============================================================================
function TimeColumn({ samples, mode, hoverY }) {
  // Render hour/depth labels and a mini depth-progress bar
  const N = samples.length;
  const labels = [];
  const step = Math.floor(N / 8);
  for (let i = step; i < N; i += step) {
    const s = samples[i];
    const t = new Date(Date.now() - (N - i) * 90 * 1000); // fake timestamps
    labels.push({
      y: (i / (N - 1)) * 100,
      time: `${String(t.getHours()).padStart(2, '0')}:${String(t.getMinutes()).padStart(2, '0')}`,
      depth: s.bitDepth,
    });
  }
  return (
    <div className="w-[110px] shrink-0 border-r border-slate-800/80 bg-[#0A0E14] relative">
      <div className="h-8 border-b border-slate-800/80 bg-[#0D1218] px-2 flex items-center">
        <span className="text-[10px] uppercase tracking-wider text-slate-500 font-semibold">
          {mode === 'time' ? 'Time' : 'Depth'}
        </span>
      </div>
      <div className="absolute left-0 right-0 top-8 bottom-0">
        {/* mini depth bar */}
        <div className="absolute left-3 top-3 bottom-3 w-3 rounded bg-[#15202E] border border-slate-800/80 overflow-hidden">
          <div className="absolute inset-x-0 bg-emerald/80" style={{ top: '8%', bottom: '18%' }} />
          {/* bit marker */}
          <div
            className="absolute left-[-4px] right-[-4px] h-0.5 bg-[#E8A21C]"
            style={{ top: '72%' }}
          />
        </div>

        {/* time/depth labels */}
        {labels.map((l, i) => (
          <div
            key={i}
            className="absolute left-8 right-1 text-[9.5px] text-slate-500 mono leading-tight"
            style={{ top: `calc(${l.y}% - 6px)` }}
          >
            {mode === 'time' ? (
              <>
                <div className="text-slate-400 font-semibold">{l.time}:00</div>
              </>
            ) : (
              <div className="text-slate-400 font-semibold tnum">{l.depth.toFixed(0)} m</div>
            )}
          </div>
        ))}

        {/* hover marker */}
        {hoverY != null && (
          <div
            className="absolute left-0 right-0 flex items-center gap-1 pointer-events-none"
            style={{ top: `calc(${hoverY * 100}% - 8px)` }}
          >
            <div className="flex-1 h-px bg-[#E8A21C]/60" />
          </div>
        )}
      </div>
    </div>
  );
}

// ============================================================================
// Tracks grid (the main chart area)
// ============================================================================
const TRACKS = [
  {
    id: 'hkl',
    label: 'Hook Load',
    channels: [
      {
        key: 'hkl',
        color: '#E8A21C',
        fill: 'rgba(232,162,28,.12)',
        min: 0,
        max: 300,
        name: 'Hook Load',
        unit: 'klbs',
      },
      {
        key: 'wob',
        color: '#12D0C2',
        fill: 'rgba(18,208,194,.18)',
        min: 0,
        max: 60,
        name: 'Block Height',
        unit: 'ft',
      },
      {
        key: 'bh',
        color: '#E8DCC0',
        fill: 'rgba(232,220,192,.08)',
        min: 0,
        max: 100,
        name: 'Block Height',
        unit: 'ft',
        thin: true,
      },
    ],
    readouts: [
      { label: 'Hook Load', key: 'hkl', unit: 'klbs', color: '#E8A21C' },
      { label: 'Bit Weight', key: 'wob', unit: 'klbs', color: '#12D0C2' },
      { label: 'Block Height', key: 'bh', unit: 'ft', color: '#E8DCC0' },
    ],
  },
  {
    id: 'rop',
    label: 'ROP · Gamma',
    channels: [
      {
        key: 'rop',
        color: '#E8A21C',
        fill: 'rgba(232,162,28,.12)',
        min: 0,
        max: 150,
        name: 'ROP - Inst',
        unit: 'ft/h',
      },
      {
        key: 'ropAvg',
        color: '#A78BFA',
        fill: 'rgba(167,139,250,.14)',
        min: 0,
        max: 150,
        name: 'ROP Avg',
        unit: 'ft/h',
      },
      {
        key: 'gamma',
        color: '#E8DCC0',
        fill: 'rgba(232,220,192,.08)',
        min: 0,
        max: 200,
        name: 'Gamma Ray',
        unit: 'gAPI',
        thin: true,
      },
    ],
    readouts: [
      { label: 'ROP - Inst', key: 'rop', unit: 'ft/h', color: '#E8A21C' },
      { label: 'ROP Avg', key: 'ropAvg', unit: 'ft/h', color: '#A78BFA' },
      { label: 'Gamma Ray', key: 'gamma', unit: 'gAPI', color: '#E8DCC0' },
    ],
  },
  {
    id: 'topdrive',
    label: 'Top Drive',
    channels: [
      {
        key: 'tdRpm',
        color: '#E8A21C',
        fill: 'rgba(232,162,28,.14)',
        min: 0,
        max: 200,
        name: 'Top Drive RPM',
        unit: 'rpm',
      },
      {
        key: 'tdTq',
        color: '#12D0C2',
        fill: 'rgba(18,208,194,.16)',
        min: 0,
        max: 25,
        name: 'Top Drive Torque',
        unit: 'klbf·ft',
      },
      {
        key: 'diff',
        color: '#A78BFA',
        fill: 'rgba(167,139,250,.14)',
        min: 0,
        max: 600,
        name: 'Diff Press',
        unit: 'psi',
      },
    ],
    readouts: [
      { label: 'Top Drive RPM', key: 'tdRpm', unit: 'rpm', color: '#E8A21C' },
      { label: 'Top Drive Torque', key: 'tdTq', unit: 'klbf·ft', color: '#12D0C2' },
      { label: 'Diff Press', key: 'diff', unit: 'psi', color: '#A78BFA' },
    ],
  },
  {
    id: 'pump',
    label: 'Pump',
    channels: [
      {
        key: 'pp',
        color: '#A78BFA',
        fill: 'rgba(167,139,250,.22)',
        min: 1500,
        max: 3500,
        name: 'Pump Pressure',
        unit: 'psi',
      },
      {
        key: 'flow',
        color: '#12D0C2',
        fill: 'rgba(18,208,194,.14)',
        min: 0,
        max: 1200,
        name: 'Flow In Rate',
        unit: 'gpm',
      },
      {
        key: 'pct',
        color: '#E8A21C',
        fill: 'rgba(232,162,28,.10)',
        min: 0,
        max: 100,
        name: 'Flow Out %',
        unit: '%',
        thin: true,
      },
    ],
    readouts: [
      { label: 'Pump Pressure', key: 'pp', unit: 'psi', color: '#A78BFA' },
      { label: 'Flow In Rate', key: 'flow', unit: 'gpm', color: '#12D0C2' },
      { label: 'Flow Out %', key: 'pct', unit: '%', color: '#E8A21C' },
    ],
  },
  {
    id: 'mud',
    label: 'Mud',
    channels: [
      {
        key: 'mud',
        color: '#12D0C2',
        fill: 'rgba(18,208,194,.14)',
        min: 400,
        max: 600,
        name: 'Mud Volume',
        unit: 'bbl',
      },
      {
        key: 'gain',
        color: '#E8A21C',
        fill: 'rgba(232,162,28,.10)',
        min: -20,
        max: 20,
        name: 'Gain/Loss',
        unit: 'bbl',
      },
      {
        key: 'gas',
        color: '#E8DCC0',
        fill: 'rgba(232,220,192,.08)',
        min: 0,
        max: 400,
        name: 'Total Gas',
        unit: 'u',
        thin: true,
      },
    ],
    readouts: [
      { label: 'Mud Volume', key: 'mud', unit: 'bbl', color: '#12D0C2' },
      { label: 'Gain/Loss', key: 'gain', unit: 'bbl', color: '#E8A21C' },
      { label: 'Total Gas', key: 'gas', unit: 'u', color: '#E8DCC0' },
    ],
  },
];

// Event annotations placed on the depth column
const EVENTS = [
  { y: 0.08, text: '09:30 · slips sliding detected by auto — auto activated', color: '#E8A21C' },
  { y: 0.18, text: '10:05 · Connection start · drilling paused', color: '#12D0C2' },
  { y: 0.31, text: 'SURVEY 10148.2 m · inc 83.0° · az 336.7°', color: '#E8DCC0' },
  { y: 0.44, text: '10:52 · pump rate change · 920 → 950 gpm', color: '#A78BFA' },
  { y: 0.58, text: '11:14 · ream 2 stands', color: '#E8A21C' },
  { y: 0.72, text: 'Connection · depth 10178.4 m', color: '#12D0C2' },
  { y: 0.86, text: '12:03 · weight to bit increased', color: '#E8DCC0' },
];

function TracksGrid({ samples, hoverY, onHoverY, latest }) {
  const gridRef = useRef(null);

  function handleMove(e) {
    const rect = gridRef.current?.getBoundingClientRect();
    if (!rect) return;
    const y = (e.clientY - rect.top) / rect.height;
    if (y >= 0 && y <= 1) onHoverY(y);
  }

  return (
    <>
      {/* Track header row (titles for each track) */}
      <div className="h-8 border-b border-slate-800/80 bg-[#0D1218] flex shrink-0">
        {TRACKS.map((t, i) => (
          <div
            key={t.id}
            className="flex-1 min-w-0 border-r border-slate-800/70 last:border-r-0 px-2 flex items-center gap-2"
          >
            {t.channels.slice(0, 3).map((c, ci) => (
              <span key={ci} className="flex items-center gap-1">
                <span className="h-2 w-2 rounded-sm" style={{ background: c.color }} />
                <span className="text-[9.5px] uppercase tracking-wider text-slate-300 font-semibold truncate">
                  {c.name}
                </span>
              </span>
            ))}
          </div>
        ))}
      </div>

      {/* Chart area */}
      <div
        ref={gridRef}
        onMouseMove={handleMove}
        onMouseLeave={() => onHoverY(null)}
        className="flex-1 min-h-0 flex relative bg-[#0A0E14]"
      >
        {TRACKS.map((t, i) => (
          <Track key={t.id} track={t} samples={samples} hoverY={hoverY} trackIndex={i} />
        ))}

        {/* event annotations layered on top */}
        <div className="absolute inset-0 pointer-events-none">
          {EVENTS.map((e, i) => (
            <div key={i} className="absolute left-1" style={{ top: `calc(${e.y * 100}% - 6px)` }}>
              <div className="flex items-center gap-1.5">
                <span className="h-1.5 w-1.5 rounded-full" style={{ background: e.color }} />
                <span
                  className="text-[9px] mono px-1 py-0.5 rounded"
                  style={{
                    color: e.color,
                    background: 'rgba(15,20,26,0.85)',
                    border: `1px solid ${e.color}55`,
                  }}
                >
                  {e.text}
                </span>
              </div>
            </div>
          ))}
        </div>

        {/* horizontal teal "connection" markers across all tracks */}
        {[0.18, 0.52, 0.78].map((y, i) => (
          <div
            key={i}
            className="absolute left-0 right-0 h-px pointer-events-none"
            style={{
              top: `${y * 100}%`,
              background: 'rgba(18,208,194,0.55)',
              boxShadow: '0 0 6px rgba(18,208,194,0.4)',
            }}
          />
        ))}

        {/* hover crosshair */}
        {hoverY != null && (
          <div
            className="absolute left-0 right-0 h-px pointer-events-none"
            style={{ top: `${hoverY * 100}%`, background: 'rgba(232,162,28,0.7)' }}
          />
        )}
      </div>

      {/* Readouts row */}
      <div className="border-t border-slate-800/80 bg-[#0D1218] flex shrink-0">
        {TRACKS.map((t) => (
          <div
            key={t.id}
            className="flex-1 min-w-0 border-r border-slate-800/70 last:border-r-0 px-2.5 py-2 space-y-1"
          >
            {t.readouts.map((r, i) => (
              <div key={i} className="flex items-baseline gap-1.5">
                <span className="text-[9.5px] uppercase tracking-wider text-slate-500 font-semibold min-w-0 truncate">
                  {r.label}
                </span>
                <span className="ml-auto flex items-baseline gap-1 shrink-0">
                  <span className="text-[14px] font-bold mono tnum" style={{ color: r.color }}>
                    {fmt(latest[r.key], r.unit)}
                  </span>
                  <span className="text-[9px] text-slate-500 mono">{r.unit}</span>
                </span>
              </div>
            ))}
          </div>
        ))}
      </div>
    </>
  );
}

function fmt(v, unit) {
  if (v == null || Number.isNaN(v)) return '—';
  if (unit === '%' || Math.abs(v) < 10) return v.toFixed(1);
  if (Math.abs(v) < 100) return v.toFixed(1);
  return v.toFixed(0);
}

// ============================================================================
// Track — vertical, depth-indexed, area-filled overlay
// ============================================================================
function Track({ track, samples, hoverY, trackIndex }) {
  const ref = useRef(null);
  const [size, setSize] = useState({ w: 240, h: 500 });
  useEffect(() => {
    if (!ref.current) return;
    const ro = new ResizeObserver(([e]) => {
      setSize({ w: e.contentRect.width, h: e.contentRect.height });
    });
    ro.observe(ref.current);
    return () => ro.disconnect();
  }, []);

  const N = samples.length;
  const pad = { t: 4, b: 4, l: 4, r: 4 };
  const iw = size.w - pad.l - pad.r;
  const ih = size.h - pad.t - pad.b;

  const y = (i) => pad.t + (i / (N - 1)) * ih; // depth -> vertical
  const xOf = (ch, v) => pad.l + ((v - ch.min) / (ch.max - ch.min)) * iw;

  return (
    <div
      ref={ref}
      className="flex-1 min-w-0 border-r border-slate-800/70 last:border-r-0 relative overflow-hidden"
    >
      {/* dotted grid verticals */}
      <svg
        className="absolute inset-0 w-full h-full"
        viewBox={`0 0 ${size.w} ${size.h}`}
        preserveAspectRatio="none"
      >
        {[0.25, 0.5, 0.75].map((f, i) => (
          <line
            key={i}
            x1={pad.l + f * iw}
            y1={pad.t}
            x2={pad.l + f * iw}
            y2={size.h - pad.b}
            stroke="#1A2330"
            strokeWidth="1"
            strokeDasharray="2 4"
          />
        ))}

        {/* channels — draw thin first then thick */}
        {[...track.channels]
          .sort((a, b) => (b.thin ? 1 : 0) - (a.thin ? 1 : 0))
          .map((ch, ci) => {
            // Build path along depth; x from value.
            const pts = samples.map((s, i) => [xOf(ch, s[ch.key]).toFixed(1), y(i).toFixed(1)]);
            const line = `M ${pts.map((p) => p.join(',')).join(' L ')}`;
            // fill: close back to min-x (left edge)
            const area = `${line} L ${xOf(ch, ch.min).toFixed(1)},${y(N - 1).toFixed(1)} L ${xOf(ch, ch.min).toFixed(1)},${y(0).toFixed(1)} Z`;

            const sw = ch.thin ? 0.8 : 1.2;
            return (
              <g key={ci} style={{ mixBlendMode: 'screen' }}>
                <path d={area} fill={ch.fill} stroke="none" />
                <path
                  d={line}
                  stroke={ch.color}
                  strokeWidth={sw}
                  fill="none"
                  strokeLinejoin="round"
                  strokeLinecap="round"
                  opacity={ch.thin ? 0.7 : 0.95}
                />
              </g>
            );
          })}
      </svg>

      {/* Range labels — min left / max right on the first track only, otherwise compact */}
      <div className="absolute inset-x-0 bottom-0 px-1.5 flex items-end justify-between pointer-events-none">
        {track.channels.slice(0, 1).map((ch, i) => (
          <React.Fragment key={i}>
            <span className="text-[8.5px] mono text-slate-600">{ch.min}</span>
            <span className="text-[8.5px] mono text-slate-600">{ch.max}</span>
          </React.Fragment>
        ))}
      </div>

      {/* hover readout */}
      {hoverY != null &&
        (() => {
          const idx = Math.round(hoverY * (N - 1));
          const sample = samples[idx];
          const pin = { x: xOf(track.channels[0], sample[track.channels[0].key]), y: y(idx) };
          return (
            <div
              className="absolute pointer-events-none"
              style={{
                left: Math.min(size.w - 70, Math.max(2, pin.x + 6)),
                top: Math.min(size.h - 40, Math.max(2, pin.y - 30)),
              }}
            >
              <div
                className="rounded bg-[#0D1218]/95 border border-slate-700 px-1.5 py-0.5 text-[9.5px] mono tnum shadow-lg"
                style={{ color: track.channels[0].color }}
              >
                {fmt(sample[track.channels[0].key])} {track.channels[0].unit}
              </div>
            </div>
          );
        })()}
    </div>
  );
}

// ============================================================================
// Right summary column — compass toolface + values
// ============================================================================
function RightSummary({ latest }) {
  return (
    <div className="w-[180px] shrink-0 border-l border-slate-800/80 bg-[#0D1218] overflow-y-auto">
      <div className="h-8 border-b border-slate-800/80 px-3 flex items-center justify-between">
        <span className="text-[10px] uppercase tracking-wider text-slate-400 font-semibold">
          Column 1
        </span>
        <button className="h-5 w-5 rounded hover:bg-slate-800 flex items-center justify-center text-slate-500">
          <Icon name="x" size={11} />
        </button>
      </div>

      <div className="p-3 flex flex-col items-center">
        <Toolface azimuth={latest.az} gtf={latest.gtf} />
      </div>

      <div className="px-3 pb-3 space-y-3">
        <SummaryValue label="Toolface Mag" value={latest.gtf.toFixed(1)} unit="deg" />
        <SummaryValue label="Svy Inclination" value={latest.inc.toFixed(1)} unit="deg" />
        <SummaryValue label="Svy Azimuth" value={latest.az.toFixed(1)} unit="deg" />
        <SummaryValue label="Svy Depth" value={latest.svyDepth.toFixed(1)} unit="m" />
        <SummaryValue label="Kill Total Gas" value="—" unit="ppm" />
        <SummaryValue label="Basic MSE" value={latest.mse.toFixed(1)} unit="kpsi" />
      </div>
    </div>
  );
}

function SummaryValue({ label, value, unit }) {
  return (
    <div className="text-center border-t border-slate-800/70 pt-2.5 first:border-t-0 first:pt-0">
      <div className="text-[10px] uppercase tracking-wider text-slate-500 font-semibold">
        {label}
      </div>
      <div className="text-[20px] font-extrabold mono tnum text-white leading-tight mt-0.5">
        {value}
      </div>
      <div className="text-[10px] mono text-slate-500">{unit}</div>
    </div>
  );
}

function Toolface({ azimuth, gtf }) {
  const size = 130;
  const cx = size / 2;
  const cy = size / 2;
  const r = 58;
  // Needle at gtf (0° = north = up)
  const a = ((gtf - 90) * Math.PI) / 180;
  const nx = cx + Math.cos(a) * (r - 8);
  const ny = cy + Math.sin(a) * (r - 8);
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`}>
      {/* outer ring */}
      <circle cx={cx} cy={cy} r={r} fill="#0A0E14" stroke="#1F2937" strokeWidth="1" />
      <circle
        cx={cx}
        cy={cy}
        r={r - 4}
        fill="none"
        stroke="#2A3544"
        strokeWidth="1"
        strokeDasharray="2 3"
      />
      <circle cx={cx} cy={cy} r={r - 18} fill="none" stroke="#1F2937" strokeWidth="1" />
      {/* ticks */}
      {Array.from({ length: 12 }).map((_, i) => {
        const aa = ((i * 30 - 90) * Math.PI) / 180;
        const x1 = cx + Math.cos(aa) * (r - 2);
        const y1 = cy + Math.sin(aa) * (r - 2);
        const x2 = cx + Math.cos(aa) * (r - 6);
        const y2 = cy + Math.sin(aa) * (r - 6);
        return (
          <line
            key={i}
            x1={x1}
            y1={y1}
            x2={x2}
            y2={y2}
            stroke={i % 3 === 0 ? '#64748B' : '#334155'}
            strokeWidth="1"
          />
        );
      })}
      {/* cardinal labels */}
      <text x={cx} y={12} fontSize="9" textAnchor="middle" fill="#94A3B8" fontFamily="monospace">
        0°
      </text>
      <text
        x={size - 8}
        y={cy + 3}
        fontSize="8"
        textAnchor="end"
        fill="#64748B"
        fontFamily="monospace"
      >
        90
      </text>
      <text
        x={cx}
        y={size - 6}
        fontSize="8"
        textAnchor="middle"
        fill="#64748B"
        fontFamily="monospace"
      >
        180
      </text>
      <text x={8} y={cy + 3} fontSize="8" fill="#64748B" fontFamily="monospace">
        270
      </text>
      {/* needle */}
      <line
        x1={cx}
        y1={cy}
        x2={nx}
        y2={ny}
        stroke="#E8A21C"
        strokeWidth="2"
        strokeLinecap="round"
      />
      <circle cx={cx} cy={cy} r="4" fill="#E8A21C" />
      <circle cx={cx} cy={cy} r="2" fill="#0A0E14" />
      {/* inner readout */}
      <text
        x={cx}
        y={cy + r + 14}
        fontSize="10"
        textAnchor="middle"
        fill="#94A3B8"
        fontFamily="monospace"
      >
        GTF {gtf.toFixed(0)}°
      </text>
    </svg>
  );
}

// ============================================================================
// Data generation
// ============================================================================
function makeDepthSeries(N, startDepth) {
  const arr = [];
  let hkl = 180;
  let wob = 38;
  let bh = 45;
  let rop = 60;
  let ropAvg = 55;
  let gamma = 90;
  let tdRpm = 120;
  let tdTq = 14;
  let diff = 300;
  let pp = 2700;
  let flow = 920;
  let pct = 33;
  let mud = 498;
  let gain = 0;
  let gas = 200;
  let inc = 83;
  let az = 336.7;
  let gtf = 108;
  let mse = 0.1;
  let bitDepth = startDepth - N * 0.5; // bit at top of window initially
  for (let i = 0; i < N; i++) {
    hkl = clamp(hkl + (Math.random() - 0.5) * 4, 140, 220);
    wob = clamp(wob + (Math.random() - 0.5) * 1.2, 20, 55);
    bh = clamp(bh + (Math.random() - 0.5) * 2, 10, 90);
    rop = clamp(rop + (Math.random() - 0.5) * 8, 10, 140);
    ropAvg = clamp(ropAvg + (Math.random() - 0.5) * 3, 20, 90);
    gamma = clamp(gamma + (Math.random() - 0.5) * 10, 30, 180);
    tdRpm = clamp(tdRpm + (Math.random() - 0.5) * 5, 60, 170);
    tdTq = clamp(tdTq + (Math.random() - 0.5) * 0.8, 5, 22);
    diff = clamp(diff + (Math.random() - 0.5) * 30, 150, 520);
    pp = clamp(pp + (Math.random() - 0.5) * 60, 2300, 3200);
    flow = clamp(flow + (Math.random() - 0.5) * 20, 700, 1050);
    pct = clamp(pct + (Math.random() - 0.5) * 3, 20, 60);
    mud = clamp(mud + (Math.random() - 0.5) * 2, 450, 560);
    gain = clamp(gain + (Math.random() - 0.5) * 1, -15, 15);
    gas = clamp(gas + (Math.random() - 0.5) * 15, 50, 380);
    inc = clamp(inc + (Math.random() - 0.5) * 0.2, 82, 84);
    az = clamp(az + (Math.random() - 0.5) * 0.3, 334, 338);
    gtf = clamp(gtf + (Math.random() - 0.5) * 2, 100, 115);
    mse = clamp(mse + (Math.random() - 0.5) * 0.05, 0.05, 0.25);
    bitDepth += 0.5;
    arr.push({
      hkl,
      wob,
      bh,
      rop,
      ropAvg,
      gamma,
      tdRpm,
      tdTq,
      diff,
      pp,
      flow,
      pct,
      mud,
      gain,
      gas,
      inc,
      az,
      gtf,
      mse,
      bitDepth,
      holeDepth: bitDepth + 0.03,
      svyDepth: bitDepth - 100 + i * 0.1,
    });
  }
  return arr;
}
function advanceDepthSeries(prev) {
  const last = prev[prev.length - 1];
  const next = {
    ...last,
    hkl: clamp(last.hkl + (Math.random() - 0.5) * 4, 140, 220),
    wob: clamp(last.wob + (Math.random() - 0.5) * 1.2, 20, 55),
    bh: clamp(last.bh + (Math.random() - 0.5) * 2, 10, 90),
    rop: clamp(last.rop + (Math.random() - 0.5) * 8, 10, 140),
    ropAvg: clamp(last.ropAvg + (Math.random() - 0.5) * 3, 20, 90),
    gamma: clamp(last.gamma + (Math.random() - 0.5) * 10, 30, 180),
    tdRpm: clamp(last.tdRpm + (Math.random() - 0.5) * 5, 60, 170),
    tdTq: clamp(last.tdTq + (Math.random() - 0.5) * 0.8, 5, 22),
    diff: clamp(last.diff + (Math.random() - 0.5) * 30, 150, 520),
    pp: clamp(last.pp + (Math.random() - 0.5) * 60, 2300, 3200),
    flow: clamp(last.flow + (Math.random() - 0.5) * 20, 700, 1050),
    pct: clamp(last.pct + (Math.random() - 0.5) * 3, 20, 60),
    mud: clamp(last.mud + (Math.random() - 0.5) * 2, 450, 560),
    gain: clamp(last.gain + (Math.random() - 0.5) * 1, -15, 15),
    gas: clamp(last.gas + (Math.random() - 0.5) * 15, 50, 380),
    gtf: clamp(last.gtf + (Math.random() - 0.5) * 2, 100, 115),
    mse: clamp(last.mse + (Math.random() - 0.5) * 0.05, 0.05, 0.25),
    bitDepth: last.bitDepth + 0.5,
    holeDepth: last.holeDepth + 0.5,
    svyDepth: last.svyDepth + 0.5,
  };
  return [...prev.slice(1), next];
}
function clamp(v, lo, hi) {
  return Math.max(lo, Math.min(hi, v));
}

// ============================================================================
// Sensor-not-enabled fallback
// ============================================================================
function SensorNotEnabled({ onEnable }) {
  return (
    <div className="view-in flex items-center justify-center py-20">
      <Card className="max-w-xl text-center p-8">
        <div className="mx-auto h-14 w-14 rounded-full bg-amber-soft flex items-center justify-center mb-4">
          <Icon name="zap" size={24} className="text-amber-ink" />
        </div>
        <CardTitle>Telemetría no habilitada</CardTitle>
        <CardDescription className="max-w-sm mx-auto mt-2">
          La telemetría en tiempo real está disponible solo si el equipo o cliente contrata el
          servicio de sensores. Activala desde la configuración del cliente o solicitá el paquete
          NETTO.
        </CardDescription>
        <div className="flex gap-2 justify-center mt-5">
          <Button variant="outline" size="sm">
            Ver planes
          </Button>
          <Button variant="primary" size="sm" onClick={onEnable}>
            Activar (demo)
          </Button>
        </div>
      </Card>
    </div>
  );
}

Object.assign(window, { TelemetriaModule });
