// ═══════════════════════════════════════════════════════════════════════════
// BarrierPath — the signature element.
//
// Not decoration: this is the object the Lab actually studies. A capital path
// under a drawdown barrier, delevering as it approaches the floor, exactly as
// in the Exp DDR rule f*(d) = κd / (1 − α) from Sukhov (2026b).
//
//   equity      — ultramarine, the realised path
//   peak        — dashed, the running maximum M_t
//   barrier     — sulphur, the floor at (1 − b) · M_t
//   leverage    — bottom band, f* collapsing toward zero at the barrier
//
// Seeded, so every visitor sees a reproducible path; reseeds on a slow loop.
// ═══════════════════════════════════════════════════════════════════════════

const BarrierPath = ({ theme }) => {
  const hostRef = React.useRef(null);
  const cvsRef = React.useRef(null);
  const hudRef = React.useRef({ d: null, f: null, n: null });

  React.useEffect(() => {
    const host = hostRef.current;
    const cvs = cvsRef.current;
    if (!host || !cvs) return;
    const ctx = cvs.getContext('2d');

    const reduce = matchMedia('(prefers-reduced-motion: reduce)').matches;

    // ── palette, resolved from the live theme tokens ──────────────────────
    let C = {};
    const readTokens = () => {
      const cs = getComputedStyle(document.documentElement);
      const g = (n) => cs.getPropertyValue(n).trim();
      C = {
        bid: g('--bid'),
        neg: g('--neg'),
        ink3: g('--ink-3'),
        ink4: g('--ink-4'),
        rule: g('--rule'),
      };
    };
    readTokens();

    // ── seeded RNG ────────────────────────────────────────────────────────
    const mulberry32 = (a) => () => {
      a |= 0; a = (a + 0x6D2B79F5) | 0;
      let t = Math.imul(a ^ (a >>> 15), 1 | a);
      t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
      return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
    };

    // ── the simulation ────────────────────────────────────────────────────
    // Log-space GBM, leverage set by distance to a 20% drawdown barrier.
    const BARRIER = 0.20;   // log-drawdown limit
    const KAPPA = 1.0;      // perceived edge, scales the cushion into leverage
    const M = 0.00062;      // drift per step
    const S = 0.0129;       // vol per step

    const simulate = (n, seed) => {
      const rnd = mulberry32(seed);
      const gauss = () => {
        let u = 0, v = 0;
        while (u === 0) u = rnd();
        while (v === 0) v = rnd();
        return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v);
      };

      const x = new Float64Array(n);   // log equity
      const peak = new Float64Array(n);
      const lev = new Float64Array(n);

      let lx = 0, lm = 0;
      for (let i = 0; i < n; i++) {
        const d = lm - lx;                                   // drawdown, log
        const cushion = Math.max(0, (BARRIER - d) / BARRIER); // 1 at peak, 0 at floor
        const f = Math.min(1, KAPPA * cushion);
        lx += f * M + f * S * gauss() - 0.5 * f * f * S * S;
        if (lx > lm) lm = lx;
        x[i] = lx; peak[i] = lm; lev[i] = f;
      }
      return { x, peak, lev, n };
    };

    // ── geometry ──────────────────────────────────────────────────────────
    let W = 0, H = 0, sim = null, dpr = 1;
    const LEV_H = 0.19;      // bottom band share given to the leverage plot
    const PAD_T = 0.10;      // headroom

    const build = () => {
      const r = host.getBoundingClientRect();
      dpr = Math.min(2, window.devicePixelRatio || 1);
      W = Math.max(320, r.width);
      H = Math.max(200, r.height);
      cvs.width = Math.round(W * dpr);
      cvs.height = Math.round(H * dpr);
      cvs.style.width = W + 'px';
      cvs.style.height = H + 'px';
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
      const steps = Math.max(360, Math.min(1400, Math.round(W * 1.35)));
      if (!sim || sim.n !== steps) sim = simulate(steps, seedRef);
    };

    let seedRef = 20260604;

    // ── drawing ───────────────────────────────────────────────────────────
    const draw = (upto) => {
      const n = sim.n;
      const k = Math.max(2, Math.min(n, Math.round(upto)));

      // vertical extent of the price plot
      const plotTop = H * PAD_T;
      const plotBot = H * (1 - LEV_H) - 14;

      let lo = Infinity, hi = -Infinity;
      for (let i = 0; i < n; i++) {
        const fl = sim.peak[i] - BARRIER;
        if (fl < lo) lo = fl;
        if (sim.peak[i] > hi) hi = sim.peak[i];
        if (sim.x[i] < lo) lo = sim.x[i];
      }
      const span = (hi - lo) || 1;
      const px = (i) => (i / (n - 1)) * W;
      const py = (v) => plotBot - ((v - lo) / span) * (plotBot - plotTop);

      ctx.clearRect(0, 0, W, H);

      // time gridlines — surveyor marks, very quiet
      ctx.strokeStyle = C.rule;
      ctx.lineWidth = 1;
      const gridStep = W / 8;
      for (let gx = gridStep; gx < W; gx += gridStep) {
        ctx.beginPath();
        ctx.moveTo(Math.round(gx) + 0.5, plotTop);
        ctx.lineTo(Math.round(gx) + 0.5, plotBot);
        ctx.stroke();
      }

      // ── forbidden zone: everything at or below the barrier ──────────────
      ctx.beginPath();
      ctx.moveTo(0, py(sim.peak[0] - BARRIER));
      for (let i = 1; i < k; i++) ctx.lineTo(px(i), py(sim.peak[i] - BARRIER));
      ctx.lineTo(px(k - 1), plotBot);
      ctx.lineTo(0, plotBot);
      ctx.closePath();
      ctx.fillStyle = C.neg;
      ctx.globalAlpha = 0.05;
      ctx.fill();
      ctx.globalAlpha = 1;

      // barrier line itself
      ctx.beginPath();
      ctx.moveTo(0, py(sim.peak[0] - BARRIER));
      for (let i = 1; i < k; i++) ctx.lineTo(px(i), py(sim.peak[i] - BARRIER));
      ctx.strokeStyle = C.neg;
      ctx.lineWidth = 1.35;
      ctx.globalAlpha = 0.85;
      ctx.stroke();
      ctx.globalAlpha = 1;

      // running maximum — dashed
      ctx.save();
      ctx.setLineDash([2, 4]);
      ctx.beginPath();
      ctx.moveTo(0, py(sim.peak[0]));
      for (let i = 1; i < k; i++) ctx.lineTo(px(i), py(sim.peak[i]));
      ctx.strokeStyle = C.ink4;
      ctx.lineWidth = 1;
      ctx.stroke();
      ctx.restore();

      // equity area
      ctx.beginPath();
      ctx.moveTo(0, py(sim.x[0]));
      for (let i = 1; i < k; i++) ctx.lineTo(px(i), py(sim.x[i]));
      ctx.lineTo(px(k - 1), plotBot);
      ctx.lineTo(0, plotBot);
      ctx.closePath();
      ctx.fillStyle = C.bid;
      ctx.globalAlpha = 0.07;
      ctx.fill();
      ctx.globalAlpha = 1;

      // equity path
      ctx.beginPath();
      ctx.moveTo(0, py(sim.x[0]));
      for (let i = 1; i < k; i++) ctx.lineTo(px(i), py(sim.x[i]));
      ctx.strokeStyle = C.bid;
      ctx.lineWidth = 1.6;
      ctx.lineJoin = 'round';
      ctx.shadowColor = C.bid;
      ctx.shadowBlur = 12;
      ctx.stroke();
      ctx.shadowBlur = 0;

      // leading marker
      const lx = px(k - 1), ly = py(sim.x[k - 1]);
      ctx.beginPath();
      ctx.arc(lx, ly, 2.6, 0, Math.PI * 2);
      ctx.fillStyle = C.bid;
      ctx.fill();
      ctx.beginPath();
      ctx.moveTo(lx, plotTop);
      ctx.lineTo(lx, plotBot);
      ctx.strokeStyle = C.bid;
      ctx.globalAlpha = 0.22;
      ctx.lineWidth = 1;
      ctx.stroke();
      ctx.globalAlpha = 1;

      // ── leverage band: f*(d) collapsing toward the floor ───────────────
      const bandTop = H * (1 - LEV_H) + 6;
      const bandBot = H - 2;
      const ly2 = (f) => bandBot - f * (bandBot - bandTop);

      ctx.beginPath();
      ctx.moveTo(0, bandBot);
      for (let i = 0; i < k; i++) ctx.lineTo(px(i), ly2(sim.lev[i]));
      ctx.lineTo(px(k - 1), bandBot);
      ctx.closePath();
      ctx.fillStyle = C.ink3;
      ctx.globalAlpha = 0.16;
      ctx.fill();
      ctx.globalAlpha = 1;

      ctx.beginPath();
      ctx.moveTo(0, ly2(sim.lev[0]));
      for (let i = 1; i < k; i++) ctx.lineTo(px(i), ly2(sim.lev[i]));
      ctx.strokeStyle = C.ink3;
      ctx.globalAlpha = 0.7;
      ctx.lineWidth = 1;
      ctx.stroke();
      ctx.globalAlpha = 1;

      // baseline of the leverage band
      ctx.beginPath();
      ctx.moveTo(0, bandBot + 0.5);
      ctx.lineTo(W, bandBot + 0.5);
      ctx.strokeStyle = C.rule;
      ctx.stroke();

      // ── in-canvas annotation ───────────────────────────────────────────
      ctx.font = '500 9.5px "IBM Plex Mono", ui-monospace, monospace';
      ctx.fillStyle = C.ink3;
      ctx.textBaseline = 'bottom';
      ctx.fillText('f*(d)  LEVERAGE', 4, bandTop - 3);
      ctx.textBaseline = 'top';
      ctx.fillStyle = C.neg;
      ctx.globalAlpha = 0.9;
      ctx.fillText('BARRIER  −20% FROM PEAK', 4, py(sim.peak[k - 1] - BARRIER) + 6);
      ctx.globalAlpha = 1;

      // ── HUD ────────────────────────────────────────────────────────────
      const dNow = sim.peak[k - 1] - sim.x[k - 1];
      const h = hudRef.current;
      if (h.d) h.d.textContent = '−' + (dNow * 100).toFixed(2) + '%';
      if (h.f) h.f.textContent = sim.lev[k - 1].toFixed(3);
      if (h.n) h.n.textContent = String(k).padStart(4, '0') + '/' + n;
    };

    // ── animation loop ────────────────────────────────────────────────────
    let raf = 0, t0 = 0, phase = 'draw', holdUntil = 0;
    const DRAW_MS = 5200, HOLD_MS = 9000;

    const frame = (t) => {
      if (!t0) t0 = t;
      if (phase === 'draw') {
        const p = Math.min(1, (t - t0) / DRAW_MS);
        const eased = 1 - Math.pow(1 - p, 2.1);
        draw(2 + eased * (sim.n - 2));
        if (p >= 1) { phase = 'hold'; holdUntil = t + HOLD_MS; }
      } else if (t > holdUntil) {
        seedRef = (seedRef * 1103515245 + 12345) & 0x7fffffff;
        sim = simulate(sim.n, seedRef);
        t0 = t; phase = 'draw';
      }
      raf = requestAnimationFrame(frame);
    };

    const start = () => {
      build();
      if (reduce) { draw(sim.n); return; }
      cancelAnimationFrame(raf);
      t0 = 0; phase = 'draw';
      raf = requestAnimationFrame(frame);
    };

    start();

    // redraw once webfonts land, so canvas labels use the real face
    if (document.fonts && document.fonts.ready) {
      document.fonts.ready.then(() => { if (sim) draw(phase === 'hold' ? sim.n : 2); });
    }

    const ro = new ResizeObserver(() => {
      const prev = sim ? sim.n : 0;
      build();
      if (reduce) draw(sim.n);
      else if (sim.n !== prev) { t0 = 0; phase = 'draw'; }
      else draw(phase === 'hold' ? sim.n : 2);
    });
    ro.observe(host);

    // pause off-screen
    const io = new IntersectionObserver((es) => {
      es.forEach((e) => {
        if (reduce) return;
        if (e.isIntersecting) { if (!raf) raf = requestAnimationFrame(frame); }
        else { cancelAnimationFrame(raf); raf = 0; }
      });
    }, { threshold: 0 });
    io.observe(host);

    return () => { cancelAnimationFrame(raf); ro.disconnect(); io.disconnect(); };
  }, [theme]);

  return (
    <div ref={hostRef} className="hero-canvas" aria-hidden="true">
      <canvas ref={cvsRef} />
      <div style={{
        position: 'absolute', top: 0, right: 0,
        borderLeft: '1px solid var(--rule)',
        borderBottom: '1px solid var(--rule)',
        display: 'grid', gridTemplateColumns: 'repeat(3, auto)',
      }}>
        {[
          ['drawdown d', (el) => (hudRef.current.d = el)],
          ['leverage f*', (el) => (hudRef.current.f = el)],
          ['step', (el) => (hudRef.current.n = el)],
        ].map(([label, ref], i) => (
          <div key={label} style={{
            padding: '9px 14px',
            borderRight: i < 2 ? '1px solid var(--rule)' : 'none',
            minWidth: 92,
          }}>
            <div className="mc" style={{ fontSize: 8 }}>{label}</div>
            <div ref={ref} className="mn" style={{
              fontSize: 12, marginTop: 4,
              color: i === 0 ? 'var(--neg)' : i === 1 ? 'var(--bid)' : 'var(--ink-3)',
            }}>—</div>
          </div>
        ))}
      </div>
    </div>
  );
};

window.BarrierPath = BarrierPath;
