/* dust.jsx — site-wide falling gold-dust background + Tweaks panel.
   Self-contained: <GoldDustControls /> owns the tweak state, renders a fixed
   full-viewport canvas behind all content, and the Tweaks panel that drives it. */
const { useRef: useRefD, useEffect: useEffectD } = React;

const DUST_DEFAULTS = /*EDITMODE-BEGIN*/{
  "dustOn": true,
  "dustDirection": "falling",
  "dustAmount": 80,
  "dustSpeed": 1,
  "dustSize": 1,
  "dustGlow": true,
  "dustPalette": ["#c19a51", "#e8cf94", "#fff4d8", "#b3893f", "#d99a52"]
}/*EDITMODE-END*/;

const DUST_PALETTES = [
  ["#c19a51", "#e8cf94", "#fff4d8", "#b3893f", "#d99a52"], // classic gold
  ["#e8cf94", "#fff4d8", "#fffaf0", "#f0dca8"],            // champagne
  ["#d98c6a", "#e7c2a0", "#f6e3cf", "#c47044"],            // warm copper
  ["#dfe7ef", "#ffffff", "#cdd8e6", "#aebfd4"],            // silver / snow
];

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

/* build a soft round sprite per color once, reuse via drawImage (fast) */
function makeSprite(color, glow) {
  const S = 64;
  const c = document.createElement('canvas');
  c.width = c.height = S;
  const ctx = c.getContext('2d');
  const g = ctx.createRadialGradient(S / 2, S / 2, 0, S / 2, S / 2, S / 2);
  g.addColorStop(0, color);
  g.addColorStop(glow ? 0.35 : 0.5, color);
  g.addColorStop(1, 'rgba(0,0,0,0)');
  ctx.fillStyle = g;
  ctx.beginPath();
  ctx.arc(S / 2, S / 2, S / 2, 0, Math.PI * 2);
  ctx.fill();
  return c;
}

function GoldDustCanvas({ on, direction, amount, speed, size, glow, palette }) {
  const canvasRef = useRefD(null);
  const sim = useRefD({ parts: [], sprites: [], raf: 0, w: 0, h: 0, dpr: 1 });

  // (re)build sprites when palette / glow changes
  useEffectD(() => {
    sim.current.sprites = palette.map((c) => makeSprite(c, glow));
  }, [palette, glow]);

  useEffectD(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    const s = sim.current;

    const resize = () => {
      s.dpr = Math.min(window.devicePixelRatio || 1, 2);
      s.w = window.innerWidth; s.h = window.innerHeight;
      canvas.width = s.w * s.dpr; canvas.height = s.h * s.dpr;
      canvas.style.width = s.w + 'px'; canvas.style.height = s.h + 'px';
      ctx.setTransform(s.dpr, 0, 0, s.dpr, 0, 0);
    };
    resize();

    const spawn = (atEdge) => {
      const falling = direction === 'falling';
      const drift = direction === 'drift';
      const r = (1.1 + Math.random() * 3.4) * size;
      return {
        x: Math.random() * s.w,
        y: atEdge
          ? (falling ? -10 - Math.random() * s.h * 0.3 : s.h + 10 + Math.random() * s.h * 0.3)
          : Math.random() * s.h,
        r,
        // base vertical velocity (px/frame @60fps); drift is gentle both ways
        vy: (drift ? (Math.random() - 0.5) * 0.25 : (0.18 + Math.random() * 0.5))
          * (falling ? 1 : -1) * (1 + (r - 2) * 0.18),
        sway: 0.3 + Math.random() * 0.9,
        swayPhase: Math.random() * Math.PI * 2,
        swaySpeed: 0.006 + Math.random() * 0.012,
        baseAlpha: 0.35 + Math.random() * 0.5,
        twPhase: Math.random() * Math.PI * 2,
        twSpeed: 0.01 + Math.random() * 0.02,
        spriteI: (Math.random() * Math.max(1, s.sprites.length)) | 0,
      };
    };

    const build = () => {
      const N = reduceMotion ? Math.min(20, amount) : amount;
      s.parts = Array.from({ length: N }, () => spawn(false));
    };
    build();

    let last = performance.now();
    const tick = (now) => {
      const dt = Math.min(2.4, (now - last) / 16.67); // frames elapsed, capped
      last = now;
      ctx.clearRect(0, 0, s.w, s.h);
      const falling = direction === 'falling';
      const drift = direction === 'drift';
      for (const p of s.parts) {
        p.y += p.vy * speed * dt;
        p.swayPhase += p.swaySpeed * dt;
        p.x += Math.sin(p.swayPhase) * p.sway * speed * dt;
        p.twPhase += p.twSpeed * dt;
        // recycle off-screen
        if (falling && p.y - p.r > s.h) { Object.assign(p, spawn(true), { y: -10 - Math.random() * 40 }); }
        else if (!falling && !drift && p.y + p.r < 0) { Object.assign(p, spawn(true), { y: s.h + 10 + Math.random() * 40 }); }
        else if (drift) {
          if (p.y - p.r > s.h) p.y = -10;
          if (p.y + p.r < 0) p.y = s.h + 10;
        }
        if (p.x < -20) p.x = s.w + 20; else if (p.x > s.w + 20) p.x = -20;

        const tw = 0.6 + 0.4 * Math.sin(p.twPhase);
        ctx.globalAlpha = Math.max(0, Math.min(1, p.baseAlpha * tw));
        const spr = s.sprites[p.spriteI % s.sprites.length];
        if (spr) {
          const d = p.r * (glow ? 4.2 : 2.6);
          ctx.drawImage(spr, p.x - d / 2, p.y - d / 2, d, d);
        }
      }
      ctx.globalAlpha = 1;
      s.raf = requestAnimationFrame(tick);
    };

    if (on) s.raf = requestAnimationFrame(tick);
    window.addEventListener('resize', resize);
    return () => { cancelAnimationFrame(s.raf); window.removeEventListener('resize', resize); };
  }, [on, direction, amount, speed, size, glow, palette]);

  if (!on) return null;
  return (
    <canvas
      ref={canvasRef}
      aria-hidden="true"
      style={{ position: 'fixed', inset: 0, width: '100%', height: '100%', pointerEvents: 'none', zIndex: 5 }}
    />
  );
}

function GoldDustControls() {
  const [t, setTweak] = useTweaks(DUST_DEFAULTS);
  return (
    <>
      <GoldDustCanvas
        on={t.dustOn}
        direction={t.dustDirection}
        amount={t.dustAmount}
        speed={t.dustSpeed}
        size={t.dustSize}
        glow={t.dustGlow}
        palette={t.dustPalette}
      />
      <TweaksPanel title="Tweaks">
        <TweakSection label="Gold dust" />
        <TweakToggle label="Show dust" value={t.dustOn} onChange={(v) => setTweak('dustOn', v)} />
        <TweakRadio label="Direction" value={t.dustDirection}
          options={['falling', 'rising', 'drift']}
          onChange={(v) => setTweak('dustDirection', v)} />
        <TweakSlider label="Amount" value={t.dustAmount} min={20} max={200} step={5}
          onChange={(v) => setTweak('dustAmount', v)} />
        <TweakSlider label="Speed" value={t.dustSpeed} min={0.2} max={3} step={0.1} unit="×"
          onChange={(v) => setTweak('dustSpeed', v)} />
        <TweakSlider label="Size" value={t.dustSize} min={0.5} max={2.5} step={0.1} unit="×"
          onChange={(v) => setTweak('dustSize', v)} />
        <TweakToggle label="Soft glow" value={t.dustGlow} onChange={(v) => setTweak('dustGlow', v)} />
        <TweakColor label="Color" value={t.dustPalette} options={DUST_PALETTES}
          onChange={(v) => setTweak('dustPalette', v)} />
      </TweaksPanel>
    </>
  );
}

Object.assign(window, { GoldDustControls });
