/* ARBEITSSCHIRM — Live-Wetter-Engine (Canvas-Partikel)
   Vier Modi: wind · regen · sturm · schnee. Sanfte Übergänge per Lerp.
   Respektiert prefers-reduced-motion (statischer, ruhiger Zustand). */
(function () {
  const MODES = {
    wind:   { rain: 0.00, rainSpeed: 15, wind: 13.0, snow: 0.00, gust: 1.00, lightning: 0, sun: 0 },
    regen:  { rain: 1.00, rainSpeed: 22, wind:  1.8, snow: 0.00, gust: 0.10, lightning: 0, sun: 0 },
    sturm:  { rain: 1.00, rainSpeed: 26, wind:  7.0, snow: 0.00, gust: 0.55, lightning: 0.011, sun: 0 },
    schnee: { rain: 0.00, rainSpeed:  0, wind:  1.8, snow: 1.00, gust: 0.30, lightning: 0, sun: 0 },
    sonne:  { rain: 0.00, rainSpeed:  0, wind:  0.8, snow: 0.00, gust: 0.00, lightning: 0, sun: 1 },
  };

  const MAX_MOTES = 90;

  const MAX_RAIN = 360;
  const MAX_SNOW = 240;
  const MAX_GUST = 120;
  const lerp = (a, b, t) => a + (b - a) * t;
  const rnd = (a, b) => a + Math.random() * (b - a);

  function createSystem(canvas, getMode, opts) {
    opts = opts || {};
    const global = !!opts.global;
    // Colours: the global overlay must read on BOTH light and dark bands,
    // so rain/gust use a mid steel and snow carries a soft shadow halo.
    const COL = global
      ? { rain: 'rgba(108,124,142,0.46)', gust: 'rgba(128,140,154,0.09)', snow: 'rgba(255,255,255,0.92)' }
      : { rain: 'rgba(176,196,214,0.42)', gust: 'rgba(204,216,228,', snow: 'rgba(255,255,255,0.85)' };
    const ctx = canvas.getContext('2d');
    let W = 0, H = 0, dpr = Math.min(window.devicePixelRatio || 1, 2);
    let raf = 0, running = true;
    const reduced = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    // current (animated) state — lerps toward the active mode target
    const cur = { rain: 0, rainSpeed: 18, wind: 4, snow: 0, gust: 0.4, lightning: 0, sun: 0 };

    const rain = Array.from({ length: MAX_RAIN }, () => ({ x: 0, y: 0, l: 0, s: 0 }));
    const snow = Array.from({ length: MAX_SNOW }, () => ({ x: 0, y: 0, r: 0, p: 0, sp: 0 }));
    const gust = Array.from({ length: MAX_GUST }, () => ({ x: 0, y: 0, l: 0, s: 0, a: 0 }));
    const motes = Array.from({ length: MAX_MOTES }, () => ({ x: 0, y: 0, r: 0, p: 0, sp: 0, a: 0 }));

    let flash = 0, boltPts = null, boltLife = 0, tSun = 0;

    function resize() {
      const rect = canvas.getBoundingClientRect();
      W = rect.width; H = rect.height;
      canvas.width = Math.max(1, Math.floor(W * dpr));
      canvas.height = Math.max(1, Math.floor(H * dpr));
      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
    }

    function seedRain(d) { d.x = rnd(-40, W + 40); d.y = rnd(0, H); d.l = rnd(12, 30); d.s = rnd(0.7, 1.25); }
    function seedSnow(f) { f.x = rnd(0, W); f.y = rnd(0, H); f.r = rnd(1.1, 3.2); f.p = rnd(0, Math.PI * 2); f.sp = rnd(0.5, 1.4); }
    function seedGust(g) { g.x = rnd(-80, W); g.y = rnd(0, H); g.l = rnd(90, 320); g.s = rnd(0.9, 2.0); g.a = rnd(0.05, 0.18); }
    function seedMote(m) { m.x = rnd(0, W); m.y = rnd(0, H); m.r = rnd(0.6, 2.0); m.p = rnd(0, Math.PI * 2); m.sp = rnd(0.12, 0.45); m.a = rnd(0.18, 0.6); }

    function seedAll() { rain.forEach(seedRain); snow.forEach(seedSnow); gust.forEach(seedGust); motes.forEach(seedMote); }

    function makeBolt() {
      const x0 = rnd(W * 0.2, W * 0.8);
      const pts = [{ x: x0, y: 0 }];
      let x = x0, y = 0;
      while (y < H * rnd(0.5, 0.85)) { y += rnd(24, 60); x += rnd(-44, 44); pts.push({ x, y }); }
      return pts;
    }

    function step() {
      if (!running) return;
      const tgt = MODES[getMode()] || MODES.sturm;
      // Density (rain/snow/gust amount) is set INSTANTLY — switching feels immediate.
      // Only motion params (wind/speed) ease a touch so it still looks natural.
      const kMove = 0.16;
      cur.rain = tgt.rain;
      cur.snow = tgt.snow;
      cur.gust = tgt.gust;
      cur.wind = lerp(cur.wind, tgt.wind, kMove);
      cur.rainSpeed = lerp(cur.rainSpeed, tgt.rainSpeed || 18, kMove);
      cur.lightning = tgt.lightning;
      cur.sun = tgt.sun || 0;

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

      // --- sun: warm glow + god rays + drifting backlit dust motes ---
      if (cur.sun > 0) {
        tSun += 0.01;
        tSun += 0.01;
        // origin sits OUTSIDE the top-right corner so no bright hotspot shows
        const gx = W * 1.04, gy = -H * 0.14;
        const grd = ctx.createRadialGradient(gx, gy, 0, gx, gy, Math.max(W, H) * 1.05);
        grd.addColorStop(0, 'rgba(255,206,128,' + (global ? 0.09 : 0.13) + ')');
        grd.addColorStop(0.45, 'rgba(255,190,110,' + (global ? 0.03 : 0.05) + ')');
        grd.addColorStop(1, 'rgba(255,190,110,0)');
        ctx.fillStyle = grd;
        ctx.fillRect(0, 0, W, H);

        // god rays: soft warm shafts fanning down-left from the off-screen sun
        const rayLen = Math.max(W, H) * 1.9;
        const RAYS = 14;
        ctx.save();
        ctx.translate(gx, gy);
        for (let i = 0; i < RAYS; i++) {
          const ang = 2.35 + (i - RAYS / 2) * 0.12 + Math.sin(tSun * 0.5 + i) * 0.01;
          const shimmer = 0.5 + 0.5 * Math.sin(tSun * 1.3 + i * 1.7);
          const a = (global ? 0.014 : 0.024) * (0.4 + 0.6 * shimmer);
          const wNear = 6, wFar = 34 + 16 * shimmer;
          ctx.save();
          ctx.rotate(ang);
          const rg = ctx.createLinearGradient(0, 0, rayLen, 0);
          rg.addColorStop(0, 'rgba(255,214,150,' + a.toFixed(3) + ')');
          rg.addColorStop(1, 'rgba(255,214,150,0)');
          ctx.fillStyle = rg;
          ctx.beginPath();
          ctx.moveTo(0, -wNear);
          ctx.lineTo(rayLen, -wFar);
          ctx.lineTo(rayLen, wFar);
          ctx.lineTo(0, wNear);
          ctx.closePath();
          ctx.fill();
          ctx.restore();
        }
        ctx.restore();

        for (let i = 0; i < MAX_MOTES; i++) {
          const m = motes[i];
          m.p += 0.012;
          m.y -= m.sp;
          m.x += Math.sin(m.p) * 0.5 + cur.wind * 0.15;
          if (m.y < -6) { m.y = H + 6; m.x = rnd(0, W); }
          if (m.x > W + 6) m.x = -6; else if (m.x < -6) m.x = W + 6;
          ctx.fillStyle = 'rgba(255,214,150,' + m.a.toFixed(2) + ')';
          ctx.beginPath();
          ctx.arc(m.x, m.y, m.r, 0, Math.PI * 2);
          ctx.fill();
        }
      }

      // --- wind gust streaks (faint, behind) ---
      const gN = Math.floor(MAX_GUST * cur.gust);
      ctx.lineCap = 'round';
      for (let i = 0; i < gN; i++) {
        const g = gust[i];
        g.x += (cur.wind * 2.8 + 4) * g.s;
        if (g.x - g.l > W + 80) seedGust(g), (g.x = -80);
        ctx.strokeStyle = (global ? 'rgba(128,140,154,' : 'rgba(204,216,228,') + g.a.toFixed(3) + ')';
        ctx.lineWidth = 1 + g.a * 4;
        ctx.beginPath();
        ctx.moveTo(g.x, g.y);
        ctx.lineTo(g.x - g.l, g.y - cur.wind * 1.2);
        ctx.stroke();
      }

      // --- rain ---
      const rN = Math.floor(MAX_RAIN * cur.rain);
      ctx.strokeStyle = COL.rain;
      ctx.lineWidth = global ? 1.25 : 1.15;
      ctx.beginPath();
      for (let i = 0; i < MAX_RAIN; i++) {
        const d = rain[i];
        d.y += cur.rainSpeed * d.s;
        d.x += cur.wind * d.s;
        if (d.y > H + 20) { d.y = -20; d.x = rnd(-40, W + 40); }
        if (i >= rN) continue;
        ctx.moveTo(d.x, d.y);
        ctx.lineTo(d.x - cur.wind * 0.9, d.y - d.l);
      }
      ctx.stroke();

      // --- snow (always advancing so the field is pre-filled across the
      //     whole height; only the active count is actually drawn) ---
      const sN = Math.floor(MAX_SNOW * cur.snow);
      for (let i = 0; i < MAX_SNOW; i++) {
        const f = snow[i];
        f.p += 0.01;
        f.y += f.sp + 0.4;
        f.x += Math.sin(f.p) * 0.8 + cur.wind * 0.35;
        if (f.y > H + 6) { f.y = -6; f.x = rnd(0, W); }
        if (f.x > W + 6) f.x = -6; else if (f.x < -6) f.x = W + 6;
        if (i >= sN) continue;
        ctx.fillStyle = COL.snow;
        if (global) { ctx.shadowColor = 'rgba(40,48,60,0.55)'; ctx.shadowBlur = 2; }
        ctx.beginPath();
        ctx.arc(f.x, f.y, f.r, 0, Math.PI * 2);
        ctx.fill();
      }
      if (global) ctx.shadowBlur = 0;

      // --- lightning (sturm only) ---
      if (cur.lightning > 0 && Math.random() < cur.lightning) { flash = 1; boltPts = makeBolt(); boltLife = 7; }
      if (flash > 0.01) {
        ctx.fillStyle = 'rgba(232,236,245,' + (flash * 0.5).toFixed(3) + ')';
        ctx.fillRect(0, 0, W, H);
        ctx.fillStyle = 'rgba(200,36,58,' + (flash * 0.14).toFixed(3) + ')';
        ctx.fillRect(0, 0, W, H);
        flash *= 0.82;
      }
      if (boltLife > 0 && boltPts) {
        ctx.strokeStyle = 'rgba(244,247,255,' + Math.min(1, boltLife / 7).toFixed(2) + ')';
        ctx.lineWidth = 2.2;
        ctx.shadowColor = 'rgba(220,230,255,0.9)';
        ctx.shadowBlur = 16;
        ctx.beginPath();
        ctx.moveTo(boltPts[0].x, boltPts[0].y);
        for (let i = 1; i < boltPts.length; i++) ctx.lineTo(boltPts[i].x, boltPts[i].y);
        ctx.stroke();
        ctx.shadowBlur = 0;
        boltLife -= 1;
      }

      raf = requestAnimationFrame(step);
    }

    function drawStatic() {
      // reduced-motion: one calm frame of faint diagonal streaks
      ctx.clearRect(0, 0, W, H);
      ctx.strokeStyle = 'rgba(176,196,214,0.16)';
      ctx.lineWidth = 1;
      ctx.beginPath();
      for (let i = 0; i < 70; i++) {
        const x = rnd(0, W), y = rnd(0, H);
        ctx.moveTo(x, y); ctx.lineTo(x - 5, y - 16);
      }
      ctx.stroke();
    }

    resize();      // sets W/H first
    seedAll();     // THEN scatter particles across the real canvas size
    const onResize = () => resize();
    window.addEventListener('resize', onResize);
    if (reduced) drawStatic(); else raf = requestAnimationFrame(step);

    return {
      destroy() { running = false; cancelAnimationFrame(raf); window.removeEventListener('resize', onResize); },
    };
  }

  function WeatherCanvas({ mode = 'sturm', global = false, style }) {
    const ref = React.useRef(null);
    const modeRef = React.useRef(mode);
    modeRef.current = mode;
    React.useEffect(() => {
      const sys = createSystem(ref.current, () => modeRef.current, { global });
      return () => sys.destroy();
    }, []);
    const base = global
      ? { position: 'fixed', inset: 0, width: '100vw', height: '100vh', pointerEvents: 'none', zIndex: 40 }
      : { position: 'absolute', inset: 0, width: '100%', height: '100%' };
    return <canvas ref={ref} aria-hidden="true" style={{ ...base, display: 'block', ...style }} />;
  }

  window.ABArbeit = Object.assign(window.ABArbeit || {}, { WeatherCanvas });
})();
