/* visuals3.jsx — Power & Heat. Heated resistor / glowing bulb.
   Reuses WaterScene + CircuitScene via shared helpers.
   The new contribution is the "thermometer + heat haze" overlay. */

const { useState: _useState3, useEffect: _useEffect3 } = React;

/* ─── WorkWheel ──────────────────────────────────────────────────
   The LOAD at the end of the pipe: a waterwheel the outflow drives.
   Spin SPEED ∝ power (the rate work happens). The counter accumulates
   ENERGY (power × time) — it keeps climbing even at low power.
   ───────────────────────────────────────────────────────────────── */
function WorkWheel({ cx, cy, r, power, kids, showLabels = true }) {
  const angleRef = React.useRef(0);
  const energyRef = React.useRef(0);
  const lastTickRef = React.useRef(0);
  const [, force] = React.useState(0);
  const pRef = React.useRef(power);
  pRef.current = power;

  React.useEffect(() => {
    let raf, last = performance.now();
    const loop = (now) => {
      const dt = Math.min(0.1, (now - last) / 1000); last = now;
      const p = pRef.current;
      const speed = p > 0.05 ? 26 + Math.min(430, p * 13) : 0;   // deg/sec ∝ power
      angleRef.current = (angleRef.current + speed * dt) % 36000;
      energyRef.current += p * dt;                                // joules = W · s
      if (now - lastTickRef.current > 33) { lastTickRef.current = now; force(n => n + 1); }
      raf = requestAnimationFrame(loop);
    };
    raf = requestAnimationFrame(loop);
    return () => cancelAnimationFrame(raf);
  }, []);

  const angle = angleRef.current;
  const E = energyRef.current;
  const eLabel = E < 1000 ? `${E.toFixed(0)} J` : `${(E / 1000).toFixed(2)} kJ`;
  const turns = Math.floor(angle / 360 + (angleRef.current >= 0 ? 0 : 0));
  const spinning = power > 0.05;

  return (
    <g>
      {/* paddles + spokes rotate; rim and hub stay. Spins CLOCKWISE:
          the pour lands on the wheel's outer RIGHT edge, driving that side down. */}
      <g transform={`rotate(${angle % 360} ${cx} ${cy})`}>
        {Array.from({ length: 8 }, (_, i) => {
          const a = (i * 45 * Math.PI) / 180;
          const x1 = cx + Math.cos(a) * 8,  y1 = cy + Math.sin(a) * 8;
          const x2 = cx + Math.cos(a) * (r - 4), y2 = cy + Math.sin(a) * (r - 4);
          // paddle: short bar perpendicular to the spoke at its tip
          const px = Math.cos(a + Math.PI / 2) * 10, py = Math.sin(a + Math.PI / 2) * 10;
          return (
            <g key={i}>
              <line x1={x1} y1={y1} x2={x2} y2={y2} stroke="var(--ink)" strokeWidth="2.5" />
              <line x1={x2 - px} y1={y2 - py} x2={x2 + px} y2={y2 + py}
                    stroke="var(--ink)" strokeWidth="4" strokeLinecap="round" />
            </g>
          );
        })}
      </g>
      <circle cx={cx} cy={cy} r={r} fill="none" stroke="var(--ink)" strokeWidth="2.5" />
      <circle cx={cx} cy={cy} r="7" fill="var(--bg-card)" stroke="var(--ink)" strokeWidth="2.5" />

      {/* droplets flung off near the impact zone when it's spinning fast */}
      {power > 6 && [0, 1, 2].map(i => (
        <circle key={i} r="2.4" fill="var(--water)" opacity="0">
          <animate attributeName="cx" values={`${cx + r * 0.55};${cx + r + 10 + i * 6}`} dur="0.7s" begin={`-${i * 0.23}s`} repeatCount="indefinite" />
          <animate attributeName="cy" values={`${cy - r * 0.75};${cy - r - 14 - i * 6};${cy - r * 0.2}`} keyTimes="0;0.5;1" dur="0.7s" begin={`-${i * 0.23}s`} repeatCount="indefinite" />
          <animate attributeName="opacity" values="0;0.8;0" dur="0.7s" begin={`-${i * 0.23}s`} repeatCount="indefinite" />
        </circle>
      ))}

      {/* watt-meter beside the wheel — the needle reads the rate of work NOW */}
      {showLabels && (() => {
        const gx = cx - r - 84, gy = cy - 24, gr = 36;
        const frac = Math.max(0, Math.min(1, power / 20));
        const aN = (-118 + frac * 236) * Math.PI / 180;
        return (
          <g>
            <line x1={cx - r - 2} y1={cy} x2={gx + gr + 2} y2={gy + 8}
                  stroke="var(--ink-faint)" strokeWidth="1.2" strokeDasharray="3 4" />
            <g transform={`translate(${gx} ${gy})`}>
              <circle r={gr} fill="var(--bg-card)" stroke="var(--ink)" strokeWidth="2.5" />
              {[0, 0.25, 0.5, 0.75, 1].map(t => {
                const a = (-118 + t * 236) * Math.PI / 180;
                return <line key={t}
                             x1={Math.sin(a) * (gr - 10)} y1={-Math.cos(a) * (gr - 10)}
                             x2={Math.sin(a) * (gr - 4)} y2={-Math.cos(a) * (gr - 4)}
                             stroke="var(--ink-faint)" strokeWidth="1.8" />;
              })}
              <line x1="0" y1="4" x2={Math.sin(aN) * (gr - 11)} y2={-Math.cos(aN) * (gr - 11)}
                    stroke="var(--current-deep)" strokeWidth="3" strokeLinecap="round" />
              <circle r="4.5" fill="var(--ink)" />
              <text y="24" textAnchor="middle" fontFamily="IBM Plex Mono, monospace"
                    fontSize="15.5" fontWeight="600"
                    fill={spinning ? "var(--current-deep)" : "var(--ink-faint)"}>
                {power.toFixed(1)} W
              </text>
              <text y={gr + 22} textAnchor="middle" fontFamily="IBM Plex Mono, monospace"
                    fontSize="13.5" fill="var(--ink-faint)" letterSpacing="0.1em">
                {kids ? "POWER METER" : "WATT METER"}
              </text>
              <text y={gr + 40} textAnchor="middle" fontFamily="IBM Plex Mono, monospace"
                    fontSize="13.5" fill="var(--ink-faint)" letterSpacing="0.08em">
                {kids ? `${turns} turns so far!` : `ENERGY · ${eLabel}`}
              </text>
            </g>
          </g>
        );
      })()}
    </g>
  );
}

/* ─── HeatedPipe ─────────────────────────────────────────────────────────
   A water pipe scene with the constriction visibly heating up.
   Heat scales with P_resistor = I² · R.
   ───────────────────────────────────────────────────────────────────────── */
function HeatedPipeScene({ voltage = 6, resistance = 3, height = 380, showLabels = true, kids = false }) {
  const W = 820, H = 460;
  const I = voltage / resistance;
  const P = I * I * resistance;             // power dissipated in the resistor
  const heatLevel = Math.max(0, Math.min(1, P / 20)); // 0..1
  const fill = fillRatio(voltage);
  const open = pipeOpenness(resistance);
  const period = flowPeriod(I);

  // Barrel + pipe (compact)
  const barrelCx = 110, barrelTop = 70, barrelBot = 370;
  const rimRx = 62, midRx = 80;
  const pipeY = 290;
  const pipeStart = barrelCx + 60;
  const pipeEnd = W - 150;
  const baseH = 34;
  const cXa = pipeStart + (pipeEnd - pipeStart) * 0.42;
  const cXb = pipeStart + (pipeEnd - pipeStart) * 0.62;
  const narrowH = baseH * (0.12 + 0.88 * open);
  // Sluice-gate pinch: opening sits on the pipe floor, and the water level
  // downstream drops to line up with it — same as Chapters 1 & 2.
  const constrictions = [{ xa: cXa, xb: cXb, narrowH, gate: true }];
  const pushFrac = narrowH / baseH;
  const pinchMid = (cXa + cXb) / 2;
  const levels = [
    { fromX: pipeStart, toX: pinchMid, frac: 1 },
    { fromX: pinchMid, toX: pipeEnd, frac: pushFrac },
  ];

  // Heat color interpolation: ink → orange → red
  const heatColor = `rgba(${196 + heatLevel * 59}, ${90 - heatLevel * 60}, ${54 - heatLevel * 40}, ${0.2 + heatLevel * 0.8})`;
  const heatGlow = heatLevel * 0.9;
  const steamCount = Math.round(heatLevel * 6);

  // The load: a waterwheel under the outlet. The outflow arcs out of the pipe
  // and lands on the wheel's outer RIGHT edge — the side travelling down.
  // Wheel sits clear to the right of the faucet spout so the pour arc reads.
  const wheelCx = pipeEnd + 50, wheelCy = pipeY + 108, wheelR = 42;
  const pour = I > 0.1;
  const pourW = 2.5 + Math.min(13, I * 2.2);
  // pour leaves from the faucet's spout mouth (renderPipe draws the tap)
  const ftS = Math.max(0.65, Math.min(1.05, baseH / 34));
  const ftTip = faucetTip({ x: pipeEnd, y: pipeY, baseH, s: ftS });
  const landX = wheelCx + wheelR * 0.78, landY = wheelCy - wheelR * 0.6;
  const pourPath = `M ${ftTip.x} ${ftTip.y} C ${ftTip.x + 18} ${ftTip.y + 26}, ${landX + 8} ${wheelCy - wheelR - 32}, ${landX} ${landY}`;

  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={height}
         preserveAspectRatio="xMidYMid meet" style={{ display: "block", maxHeight: height }}>
      {renderBarrel({ cx: barrelCx, top: barrelTop, bot: barrelBot, rimRx, midRx, fill, idSuffix: "ht", deepWater: true })}

      {/* heat halo behind the constriction */}
      <ellipse cx={(cXa + cXb) / 2} cy={pipeY} rx="90" ry="60"
               fill={heatColor} opacity={heatGlow}
               style={{ transition: "opacity 240ms ease, fill 240ms ease" }} />

      {renderPipe({ pipeStart, pipeEnd, pipeY, baseH, constrictions, current: I, period, idSuffix: "ht", levels })}

      {/* outflow pours onto the wheel — the LOAD where the work gets done */}
      {pour && (
        <>
          <path d={pourPath} fill="none" stroke="var(--water)" strokeWidth={pourW}
                strokeLinecap="round" opacity="0.55" />
          <ellipse cx={landX} cy={landY + 2} rx={6 + I} ry="3"
                   fill="var(--water)" opacity="0.35" transform={`rotate(38 ${landX} ${landY + 2})`}>
            <animate attributeName="opacity" values="0.2;0.45;0.2" dur="0.8s" repeatCount="indefinite" />
          </ellipse>
        </>
      )}
      <WorkWheel cx={wheelCx} cy={wheelCy} r={wheelR} power={P} kids={kids} showLabels={showLabels} />

      {/* steam rising above the constriction when hot */}
      {Array.from({ length: steamCount }, (_, i) => {
        const x = (cXa + cXb) / 2 + (i - steamCount / 2) * 16;
        const startY = pipeY - baseH - 8;
        return (
          <circle key={i} cx={x} cy={startY} r="6" fill="var(--bg-card)"
                  stroke="var(--ink-faint)" strokeWidth="0.8" opacity="0">
            <animate attributeName="cy" from={startY} to={startY - 80}
                     dur="2.4s" begin={`-${i * 0.3}s`} repeatCount="indefinite" />
            <animate attributeName="opacity" values="0;0.6;0"
                     dur="2.4s" begin={`-${i * 0.3}s`} repeatCount="indefinite" />
            <animate attributeName="r" from="4" to="14"
                     dur="2.4s" begin={`-${i * 0.3}s`} repeatCount="indefinite" />
          </circle>
        );
      })}

      {/* compact thermometer AT the pinch — the heat lives at the resistor */}
      <g transform={`translate(${cXb + 44} ${pipeY - baseH - 116}) scale(0.78)`}>
        <rect x="-12" y="0" width="24" height="100" rx="12"
              fill="var(--bg-card)" stroke="var(--ink)" strokeWidth="2" />
        <circle cx="0" cy="100" r="18" fill="var(--bg-card)" stroke="var(--ink)" strokeWidth="2" />
        <rect x="-6" y={100 - 90 * heatLevel} width="12" height={90 * heatLevel + 22} rx="6"
              fill={`oklch(${0.65 - heatLevel * 0.18} ${0.22 + heatLevel * 0.05} ${50 - heatLevel * 25})`}
              style={{ transition: "all 240ms ease" }} />
        <circle cx="0" cy="100" r="12"
                fill={`oklch(${0.65 - heatLevel * 0.18} ${0.22 + heatLevel * 0.05} ${50 - heatLevel * 25})`}
                style={{ transition: "fill 240ms ease" }} />
        {[0, 0.5, 1].map(t => (
          <line key={t} x1="-18" y1={100 - 90 * t} x2="-13" y2={100 - 90 * t}
                stroke="var(--ink-faint)" strokeWidth="1" />
        ))}
        {showLabels && (
          <text x="22" y="8" fontFamily="IBM Plex Mono, monospace" fontSize="15"
                fill="var(--ink-faint)" letterSpacing="0.1em">HOT</text>
        )}
      </g>

      {showLabels && (
        <g fontFamily="IBM Plex Mono, monospace" letterSpacing="0.14em">
          <text x={barrelCx - midRx + 6} y={barrelTop - 22} fontSize="24.5" fill="var(--water)">
            PRESSURE · {voltage.toFixed(1)}V
          </text>
          <text x={(cXa + cXb) / 2} y={pipeY + baseH + 36} fontSize="19"
                fill="var(--current-deep)" textAnchor="middle">
            HEAT · {P.toFixed(1)}W
          </text>
        </g>
      )}
    </svg>
  );
}

/* ─── BulbHeatScene ──────────────────────────────────────────────────────
   Circuit with a lamp whose glow + temperature scale with power.
   ───────────────────────────────────────────────────────────────────────── */
function BulbHeatScene({ voltage = 6, resistance = 3, height = 380, showLabels = true }) {
  const W = 820, H = 460;
  const I = voltage / resistance;
  const P = voltage * I;
  const period = flowPeriod(I);
  const flowing = I > 0.05;
  const heatLevel = Math.max(0, Math.min(1, P / 20));

  const L = 130, R = 690, T = 130, B = 340;
  const batCx = L, batCy = (T + B) / 2, batHalfH = 32;
  const resCx = (L + R) / 2, resCy = T;
  const bulbCx = R, bulbCy = (T + B) / 2, bulbR = 36;

  const wirePath = `
    M ${L} ${batCy - batHalfH}
    L ${L} ${T}
    L ${resCx - 50} ${T}
    M ${resCx + 50} ${T}
    L ${R} ${T}
    L ${R} ${bulbCy - bulbR}
    M ${R} ${bulbCy + bulbR}
    L ${R} ${B}
    L ${L} ${B}
    L ${L} ${batCy + batHalfH}
  `;
  const loopPath = `
    M ${L} ${batCy - batHalfH}
    L ${L} ${T} L ${R} ${T} L ${R} ${B} L ${L} ${B}
    L ${L} ${batCy + batHalfH} L ${L} ${batCy - batHalfH} Z
  `;

  return (
    <svg viewBox={`0 0 ${W} ${H}`} width="100%" height={height}
         preserveAspectRatio="xMidYMid meet" style={{ display: "block", maxHeight: height }}>
      <path d={wirePath} fill="none" stroke="var(--current-faint)"
            strokeWidth="9" strokeLinecap="round"
            opacity={flowing ? 0.55 : 0} style={{ transition: "opacity 200ms ease" }} />
      <path d={wirePath} fill="none" stroke="var(--ink)" strokeWidth="2.5" strokeLinecap="round" />

      {renderElectrons({ path: loopPath, period, flowing, count: 6 })}

      {renderBatterySymbol({ cx: batCx, cy: batCy, halfH: batHalfH, voltage, showLabel: showLabels })}
      {renderResistorSymbol({ cx: resCx, cy: resCy, w: 100, h: 32, r: resistance,
                              label: showLabels && `R · ${resistance.toFixed(1)}Ω` })}

      {/* enlarged bulb with halo and filament heat */}
      <g>
        <radialGradient id="big-bulb-glow" cx="50%" cy="50%" r="50%">
          <stop offset="0%"  stopColor="var(--current-deep)" stopOpacity="0.95"/>
          <stop offset="55%" stopColor="var(--current)" stopOpacity="0.4"/>
          <stop offset="100%" stopColor="var(--current)" stopOpacity="0"/>
        </radialGradient>
        <circle cx={bulbCx} cy={bulbCy} r={120}
                fill="url(#big-bulb-glow)" opacity={heatLevel}
                style={{ transition: "opacity 200ms ease" }} />
        <circle cx={bulbCx} cy={bulbCy} r={bulbR}
                fill={`oklch(${0.94 - heatLevel * 0.2} ${heatLevel * 0.18} ${70 + heatLevel * 30})`}
                stroke="var(--ink)" strokeWidth="2.5"
                style={{ transition: "fill 200ms ease" }} />
        {/* filament X */}
        <path d={`M ${bulbCx - 22} ${bulbCy - 22} L ${bulbCx + 22} ${bulbCy + 22}
                  M ${bulbCx + 22} ${bulbCy - 22} L ${bulbCx - 22} ${bulbCy + 22}`}
              stroke={flowing ? "var(--current-deep)" : "var(--ink-soft)"} strokeWidth="3"
              style={{ transition: "stroke 200ms ease" }} />
        {showLabels && (
          <text x={bulbCx + bulbR + 18} y={bulbCy + 4}
                fontFamily="IBM Plex Mono, monospace" fontSize="21.5"
                fill="var(--ink-faint)" letterSpacing="0.14em">
            P = {P.toFixed(1)}W
          </text>
        )}
      </g>

      {showLabels && (
        <g fontFamily="IBM Plex Mono, monospace" letterSpacing="0.14em">
          <text x={(L + R) / 2} y={B + 32}
                fontSize="21.5" fill={flowing ? "var(--current)" : "var(--ink-faint)"}
                textAnchor="middle" style={{ transition: "fill 200ms ease" }}>
            I = {I.toFixed(2)}A  ·  V·I = {P.toFixed(1)}W
          </text>
        </g>
      )}
    </svg>
  );
}

Object.assign(window, { HeatedPipeScene, BulbHeatScene });
