/* Mini interactive signal-phase demo. User adjusts:
   - NS green duration
   - EW green duration
   - Cycle offset
   And sees: a small junction with vehicles + a phase ring showing
   when each direction is green/amber/red, plus computed throughput. */

function SignalDemo() {
  const [ns, setNs] = React.useState(28);
  const [ew, setEw] = React.useState(22);
  const [arrival, setArrival] = React.useState(60); // arrivals/min total
  const canvasRef = React.useRef(null);
  const ringRef = React.useRef(null);
  const cars = React.useRef([]);
  const phaseRef = React.useRef({ phase: 0, t: 0 });
  const arrivalRef = React.useRef(0);
  const [stats, setStats] = React.useState({ throughput: 0, avgDelay: 0, queue: 0 });

  // Phase durations (s): NS green, NS amber (3), EW green, EW amber (3)
  const durs = [ns, 3, ew, 3];
  const cycle = ns + ew + 6;

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d");
    let raf, mounted = true;

    const resize = () => {
      const r = canvas.getBoundingClientRect();
      const dpr = Math.min(2, window.devicePixelRatio || 1);
      canvas.width = r.width * dpr;
      canvas.height = r.height * dpr;
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    };
    resize();
    const ro = new ResizeObserver(resize);
    ro.observe(canvas);

    let lastT = performance.now();
    let totalPassed = 0;
    let waitSum = 0;
    let waitCt = 0;

    const tick = (t) => {
      if (!mounted) return;
      const dt = Math.min(0.05, (t - lastT) / 1000);
      lastT = t;
      const r = canvas.getBoundingClientRect();
      const W = r.width, H = r.height;
      const cx = W / 2, cy = H / 2;

      // phase
      phaseRef.current.t += dt;
      const cd = durs;
      while (phaseRef.current.t > cd[phaseRef.current.phase]) {
        phaseRef.current.t -= cd[phaseRef.current.phase];
        phaseRef.current.phase = (phaseRef.current.phase + 1) % 4;
      }

      // spawn
      arrivalRef.current += dt;
      const spawnInt = 60 / Math.max(1, arrival);
      while (arrivalRef.current > spawnInt) {
        arrivalRef.current -= spawnInt;
        const dir = Math.floor(Math.random() * 4);
        const off = 11;
        let car = { dir, speed: 50, target: 50, color: ["#e9bf4a","#5fb1d0","#f1e8d6","#a8b3cc"][Math.floor(Math.random()*4)] , passed: false, waitStart: 0, totalWait: 0 };
        if (dir === 0) Object.assign(car, { x: cx + off, y: -16, vx: 0, vy: 1 });
        if (dir === 2) Object.assign(car, { x: cx - off, y: H + 16, vx: 0, vy: -1 });
        if (dir === 1) Object.assign(car, { x: W + 16, y: cy + off, vx: -1, vy: 0 });
        if (dir === 3) Object.assign(car, { x: -16, y: cy - off, vx: 1, vy: 0 });
        if (cars.current.length < 80) cars.current.push(car);
      }

      // bg
      ctx.fillStyle = "#0d1320";
      ctx.fillRect(0, 0, W, H);
      const roadWidth = 50;
      ctx.fillStyle = "#13192a";
      ctx.fillRect(0, cy - roadWidth/2, W, roadWidth);
      ctx.fillRect(cx - roadWidth/2, 0, roadWidth, H);

      // dashes
      ctx.strokeStyle = "#475377";
      ctx.setLineDash([5, 7]);
      ctx.beginPath(); ctx.moveTo(0, cy); ctx.lineTo(cx - roadWidth/2, cy); ctx.stroke();
      ctx.beginPath(); ctx.moveTo(cx + roadWidth/2, cy); ctx.lineTo(W, cy); ctx.stroke();
      ctx.beginPath(); ctx.moveTo(cx, 0); ctx.lineTo(cx, cy - roadWidth/2); ctx.stroke();
      ctx.beginPath(); ctx.moveTo(cx, cy + roadWidth/2); ctx.lineTo(cx, H); ctx.stroke();
      ctx.setLineDash([]);

      // signals
      const ph = phaseRef.current.phase;
      const nsGo = ph === 0;
      const nsAm = ph === 1;
      const ewGo = ph === 2;
      const ewAm = ph === 3;
      const colorFor = (go, am) => go ? "#3aa766" : am ? "#e9bf4a" : "#e8473a";

      const drawLight = (x, y, c) => {
        ctx.fillStyle = "#1c2236";
        ctx.fillRect(x-5, y-5, 10, 10);
        ctx.fillStyle = c;
        ctx.beginPath(); ctx.arc(x, y, 2.4, 0, Math.PI*2); ctx.fill();
        ctx.fillStyle = c + "44";
        ctx.beginPath(); ctx.arc(x, y, 5, 0, Math.PI*2); ctx.fill();
      };
      drawLight(cx + roadWidth/2 + 10, cy - roadWidth/2 - 10, colorFor(ewGo, ewAm));
      drawLight(cx - roadWidth/2 - 10, cy + roadWidth/2 + 10, colorFor(ewGo, ewAm));
      drawLight(cx + roadWidth/2 + 10, cy + roadWidth/2 + 10, colorFor(nsGo, nsAm));
      drawLight(cx - roadWidth/2 - 10, cy - roadWidth/2 - 10, colorFor(nsGo, nsAm));

      // update cars
      let queueCt = 0;
      const stopN = cy - roadWidth/2 - 4;
      const stopS = cy + roadWidth/2 + 4;
      const stopE = cx + roadWidth/2 + 4;
      const stopW = cx - roadWidth/2 - 4;
      for (const c of cars.current) {
        const isNS = c.dir === 0 || c.dir === 2;
        const greenForMe = (isNS && nsGo) || (!isNS && ewGo);
        const amberForMe = (isNS && nsAm) || (!isNS && ewAm);
        let toStop = 9999;
        if (c.dir === 0) toStop = stopN - c.y;
        if (c.dir === 2) toStop = c.y - stopS;
        if (c.dir === 1) toStop = c.x - stopE;
        if (c.dir === 3) toStop = stopW - c.x;
        let aheadGap = 9999;
        for (const o of cars.current) {
          if (o === c || o.dir !== c.dir) continue;
          if (c.dir === 0 && o.y > c.y && Math.abs(o.x - c.x) < 6) aheadGap = Math.min(aheadGap, o.y - c.y);
          if (c.dir === 2 && o.y < c.y && Math.abs(o.x - c.x) < 6) aheadGap = Math.min(aheadGap, c.y - o.y);
          if (c.dir === 1 && o.x < c.x && Math.abs(o.y - c.y) < 6) aheadGap = Math.min(aheadGap, c.x - o.x);
          if (c.dir === 3 && o.x > c.x && Math.abs(o.y - c.y) < 6) aheadGap = Math.min(aheadGap, o.x - c.x);
        }
        let target = 50;
        if (toStop > 0 && toStop < 45 && !greenForMe) target = Math.min(target, Math.max(0, (toStop - 4) * 5));
        if (amberForMe && toStop > 25) target = 0;
        if (aheadGap < 22) target = Math.min(target, Math.max(0, (aheadGap - 16) * 5));
        c.speed += (target - c.speed) * Math.min(1, dt * 5);
        if (c.speed < 1) {
          if (!c.waitStart) c.waitStart = t;
          queueCt++;
        } else if (c.waitStart) {
          c.totalWait += (t - c.waitStart) / 1000;
          c.waitStart = 0;
        }
        c.x += c.vx * c.speed * dt;
        c.y += c.vy * c.speed * dt;
        if (!c.passed) {
          if ((c.dir===0 && c.y > cy) || (c.dir===2 && c.y < cy) ||
              (c.dir===1 && c.x < cx) || (c.dir===3 && c.x > cx)) {
            c.passed = true;
            totalPassed++;
            waitSum += c.totalWait;
            waitCt++;
          }
        }
      }
      cars.current = cars.current.filter(c => c.x > -30 && c.x < W + 30 && c.y > -30 && c.y < H + 30);

      // draw cars
      for (const c of cars.current) {
        ctx.save();
        ctx.translate(c.x, c.y);
        const horiz = c.dir === 1 || c.dir === 3;
        const w = horiz ? 16 : 8;
        const h = horiz ? 8 : 16;
        ctx.fillStyle = c.color;
        ctx.fillRect(-w/2, -h/2, w, h);
        ctx.restore();
      }

      // phase ring
      const ringCanvas = ringRef.current;
      if (ringCanvas) {
        const rctx = ringCanvas.getContext("2d");
        const rr = ringCanvas.getBoundingClientRect();
        const dpr = Math.min(2, window.devicePixelRatio || 1);
        if (ringCanvas.width !== rr.width * dpr) {
          ringCanvas.width = rr.width * dpr;
          ringCanvas.height = rr.height * dpr;
          rctx.setTransform(dpr, 0, 0, dpr, 0, 0);
        }
        const RW = rr.width, RH = rr.height;
        rctx.clearRect(0, 0, RW, RH);
        const RC = Math.min(RW, RH) / 2 - 6;
        const rcx = RW / 2, rcy = RH / 2;
        let acc = 0;
        const seg = [
          { dur: ns, color: "#3aa766", label: "NS GO" },
          { dur: 3, color: "#e9bf4a", label: "AMBER" },
          { dur: ew, color: "#3aa766", label: "EW GO" },
          { dur: 3, color: "#e9bf4a", label: "AMBER" },
        ];
        for (const s of seg) {
          const start = (acc / cycle) * Math.PI * 2 - Math.PI / 2;
          const end = ((acc + s.dur) / cycle) * Math.PI * 2 - Math.PI / 2;
          rctx.strokeStyle = s.color;
          rctx.lineWidth = 12;
          rctx.beginPath();
          rctx.arc(rcx, rcy, RC, start, end);
          rctx.stroke();
          acc += s.dur;
        }
        // current phase indicator
        const phaseDurs = [ns, 3, ew, 3];
        let elapsed = 0;
        for (let i = 0; i < phaseRef.current.phase; i++) elapsed += phaseDurs[i];
        elapsed += phaseRef.current.t;
        const angle = (elapsed / cycle) * Math.PI * 2 - Math.PI / 2;
        const pX = rcx + Math.cos(angle) * RC;
        const pY = rcy + Math.sin(angle) * RC;
        rctx.fillStyle = "#0d1320";
        rctx.beginPath(); rctx.arc(pX, pY, 7, 0, Math.PI*2); rctx.fill();
        rctx.fillStyle = "#f1e8d6";
        rctx.beginPath(); rctx.arc(pX, pY, 3.5, 0, Math.PI*2); rctx.fill();
        // center text
        rctx.fillStyle = "#f1e8d6";
        rctx.font = "500 22px 'Space Grotesk', sans-serif";
        rctx.textAlign = "center";
        rctx.textBaseline = "middle";
        rctx.fillText(`${cycle}s`, rcx, rcy - 4);
        rctx.font = "10px 'IBM Plex Mono', monospace";
        rctx.fillStyle = "#94a3c4";
        rctx.fillText("CYCLE", rcx, rcy + 14);
      }

      // throughput estimation: cars passed in last 60s window approximated
      // simple: capacity per cycle = (ns + ew) * arrivalSat, here we use observed
      const expectedThroughput = Math.round((ns + ew) / cycle * arrival);
      if (Math.floor(t / 250) !== Math.floor(lastT / 250 - 1)) {
        setStats({
          throughput: expectedThroughput,
          avgDelay: waitCt ? +(waitSum / waitCt).toFixed(1) : 0,
          queue: queueCt,
        });
      }

      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => { mounted = false; cancelAnimationFrame(raf); ro.disconnect(); };
  }, [ns, ew, arrival]);

  return (
    <div className="demo-grid">
      <div className="demo-canvas-wrap">
        <canvas ref={canvasRef} style={{ width: "100%", height: "100%", display: "block", borderRadius: 12 }}></canvas>
        <div style={{
          position: "absolute", top: 28, left: 28,
          fontFamily: "var(--mono)", fontSize: 10, letterSpacing: "0.08em",
          color: "color-mix(in oklch, var(--bone) 65%, transparent)",
          textTransform: "uppercase",
          background: "color-mix(in oklch, var(--ink) 75%, transparent)",
          border: "1px solid color-mix(in oklch, var(--bone) 14%, transparent)",
          padding: "5px 9px", borderRadius: 4
        }}>
          ◉ JUNCTION SANDBOX · {arrival} arrivals/min
        </div>
      </div>

      <div className="demo-side">
        <div className="eyebrow">Try it</div>
        <h3>Tune a signal cycle. Watch flow respond.</h3>
        <p style={{ color: "var(--slate-2)", fontSize: 15, margin: "0 0 12px", maxWidth: "44ch" }}>
          A working sandbox of one of our signal-design models. Adjust phases and arrival rate;
          throughput, queue, and average delay update in real time.
        </p>

        <div className="demo-controls">
          <div className="row">
            <span className="lab">North–South green</span>
            <span className="val">{ns}s</span>
            <input type="range" min="8" max="60" value={ns} onChange={e => setNs(+e.target.value)} />
          </div>
          <div className="row">
            <span className="lab">East–West green</span>
            <span className="val">{ew}s</span>
            <input type="range" min="8" max="60" value={ew} onChange={e => setEw(+e.target.value)} />
          </div>
          <div className="row">
            <span className="lab">Arrival rate</span>
            <span className="val">{arrival}/min</span>
            <input type="range" min="20" max="160" value={arrival} onChange={e => setArrival(+e.target.value)} />
          </div>
        </div>

        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16, marginTop: 16, alignItems: "center" }}>
          <canvas ref={ringRef} style={{ width: "100%", aspectRatio: "1/1", display: "block" }}></canvas>
          <div style={{ display: "grid", gap: 10 }}>
            <div>
              <div style={{ fontFamily: "var(--mono)", fontSize: 10, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--slate)" }}>Throughput</div>
              <div style={{ fontFamily: "var(--display)", fontSize: 30, fontWeight: 500 }}>{stats.throughput}<span style={{ fontFamily: "var(--mono)", fontSize: 12, color: "var(--slate)", marginLeft: 6 }}>veh/min</span></div>
            </div>
            <div>
              <div style={{ fontFamily: "var(--mono)", fontSize: 10, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--slate)" }}>Avg delay</div>
              <div style={{ fontFamily: "var(--display)", fontSize: 30, fontWeight: 500 }}>{stats.avgDelay}<span style={{ fontFamily: "var(--mono)", fontSize: 12, color: "var(--slate)", marginLeft: 6 }}>s</span></div>
            </div>
            <div>
              <div style={{ fontFamily: "var(--mono)", fontSize: 10, letterSpacing: "0.08em", textTransform: "uppercase", color: "var(--slate)" }}>Queue (live)</div>
              <div style={{ fontFamily: "var(--display)", fontSize: 30, fontWeight: 500 }}>{stats.queue}</div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

window.SignalDemo = SignalDemo;
