/* EireneEduCloud — HTML5 canvas animation engine
   Eirene Technologies Limited
   Data-driven educational animations. Pure JS/Canvas — no external files, no assets,
   so it is fully offline and tender-compliant (HTML5 animation; no GIF/SVG asset files).
   A lesson references an animation by { key, caption, params }. Unknown keys fall back
   to a generic animated diagram so every reference renders something meaningful. */
(function (w, d) {
  var TEAL = '#0D5C6B', TEALD = '#0A4A57', GOLD = '#D4A017', SLATE = '#2C3E50', WHITE = '#fff', BLUE = '#3498DB', GREEN = '#27AE60';
  var reduced = w.matchMedia && w.matchMedia('(prefers-reduced-motion: reduce)').matches;

  function rr(ctx, x, y, ww, hh, r) { ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + ww, y, x + ww, y + hh, r); ctx.arcTo(x + ww, y + hh, x, y + hh, r); ctx.arcTo(x, y + hh, x, y, r); ctx.arcTo(x, y, x + ww, y, r); ctx.closePath(); }
  function label(ctx, t, x, y, c, size, align) { ctx.fillStyle = c || SLATE; ctx.font = '600 ' + (size || 14) + 'px Segoe UI, Arial, sans-serif'; ctx.textAlign = align || 'center'; ctx.textBaseline = 'middle'; ctx.fillText(t, x, y); }

  var SCENES = {
    // generic: pulsing concept node
    pulse: function (ctx, t, W, H, p) {
      var cx = W / 2, cy = H / 2, r = 36 + 8 * Math.sin(t * 2);
      ctx.fillStyle = TEAL; ctx.globalAlpha = 0.15; ctx.beginPath(); ctx.arc(cx, cy, r + 26, 0, 7); ctx.fill(); ctx.globalAlpha = 1;
      ctx.fillStyle = TEAL; ctx.beginPath(); ctx.arc(cx, cy, r, 0, 7); ctx.fill();
      label(ctx, (p && p.label) || '★', cx, cy, WHITE, 22);
    },
    // number line with a hopping dot
    numberline: function (ctx, t, W, H, p) {
      var y = H / 2, x0 = 40, x1 = W - 40, n = 10, step = (x1 - x0) / n;
      ctx.strokeStyle = SLATE; ctx.lineWidth = 2; ctx.beginPath(); ctx.moveTo(x0, y); ctx.lineTo(x1, y); ctx.stroke();
      for (var i = 0; i <= n; i++) { var x = x0 + i * step; ctx.beginPath(); ctx.moveTo(x, y - 6); ctx.lineTo(x, y + 6); ctx.stroke(); label(ctx, '' + i, x, y + 18, SLATE, 11); }
      var pos = (Math.floor(t) % n); var frac = t - Math.floor(t); var hop = Math.sin(frac * Math.PI) * 26;
      var dx = x0 + (pos + frac) * step;
      ctx.fillStyle = GOLD; ctx.beginPath(); ctx.arc(dx, y - hop - 10, 9, 0, 7); ctx.fill();
    },
    // growing bar chart
    bargrow: function (ctx, t, W, H, p) {
      var vals = (p && p.values) || [3, 6, 4, 8, 5], n = vals.length, bw = (W - 60) / n, mx = Math.max.apply(null, vals);
      var g = Math.min(1, (t % 4) / 1.5);
      for (var i = 0; i < n; i++) {
        var h = (vals[i] / mx) * (H - 50) * g, x = 40 + i * bw, y = H - 24 - h;
        ctx.fillStyle = i % 2 ? TEAL : GOLD; rr(ctx, x + 6, y, bw - 14, h, 4); ctx.fill();
      }
      ctx.strokeStyle = SLATE; ctx.beginPath(); ctx.moveTo(34, H - 24); ctx.lineTo(W - 20, H - 24); ctx.stroke();
    },
    // animated pie (fraction / percentage)
    pie: function (ctx, t, W, H, p) {
      var cx = W / 2, cy = H / 2, r = Math.min(W, H) / 2 - 24, frac = (p && p.fraction) || 0.66;
      var sweep = Math.min(frac, (t % 4) / 2) * 7 - 1.57;
      ctx.fillStyle = '#e4eaec'; ctx.beginPath(); ctx.arc(cx, cy, r, 0, 7); ctx.fill();
      ctx.fillStyle = TEAL; ctx.beginPath(); ctx.moveTo(cx, cy); ctx.arc(cx, cy, r, -1.57, sweep); ctx.closePath(); ctx.fill();
      label(ctx, Math.round(Math.min(frac, (t % 4) / 2) * 100) + '%', cx, cy, SLATE, 18);
    },
    // atom: nucleus + orbiting electrons
    atom: function (ctx, t, W, H, p) {
      var cx = W / 2, cy = H / 2, shells = (p && p.shells) || [2, 4];
      ctx.strokeStyle = '#cfd8dc';
      shells.forEach(function (cnt, s) {
        var R = 30 + s * 34; ctx.beginPath(); ctx.arc(cx, cy, R, 0, 7); ctx.stroke();
        for (var e = 0; e < cnt; e++) { var a = t * (1.2 - s * 0.3) + e * (6.283 / cnt); var ex = cx + R * Math.cos(a), ey = cy + R * Math.sin(a); ctx.fillStyle = BLUE; ctx.beginPath(); ctx.arc(ex, ey, 6, 0, 7); ctx.fill(); }
      });
      ctx.fillStyle = TEAL; ctx.beginPath(); ctx.arc(cx, cy, 16, 0, 7); ctx.fill(); label(ctx, '+', cx, cy, WHITE, 16);
    },
    // travelling transverse wave
    wave: function (ctx, t, W, H, p) {
      ctx.strokeStyle = TEAL; ctx.lineWidth = 3; ctx.beginPath();
      for (var x = 20; x < W - 20; x++) { var y = H / 2 + 28 * Math.sin((x / 34) - t * 3); if (x === 20) ctx.moveTo(x, y); else ctx.lineTo(x, y); }
      ctx.stroke();
      ctx.strokeStyle = '#cfd8dc'; ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(20, H / 2); ctx.lineTo(W - 20, H / 2); ctx.stroke();
    },
    // electric circuit with moving current
    circuit: function (ctx, t, W, H, p) {
      var x = 40, y = 30, ww = W - 80, hh = H - 60;
      ctx.strokeStyle = SLATE; ctx.lineWidth = 3; rr(ctx, x, y, ww, hh, 10); ctx.stroke();
      // battery
      ctx.fillStyle = GOLD; ctx.fillRect(x - 4, y + hh / 2 - 14, 8, 28); label(ctx, '🔋', x + 18, y + hh / 2, SLATE, 14);
      // bulb
      ctx.fillStyle = (Math.sin(t * 3) > 0 ? GOLD : '#f3e2a8'); ctx.beginPath(); ctx.arc(x + ww, y + hh / 2, 11, 0, 7); ctx.fill();
      // current dots
      var per = 2 * (ww + hh), dist = (t * 120) % per;
      for (var k = 0; k < 6; k++) { var dd = (dist + k * per / 6) % per, pt = perim(x, y, ww, hh, dd); ctx.fillStyle = BLUE; ctx.beginPath(); ctx.arc(pt[0], pt[1], 4, 0, 7); ctx.fill(); }
    },
    // water cycle loop
    watercycle: function (ctx, t, W, H, p) {
      ctx.fillStyle = '#7fc5d6'; ctx.fillRect(20, H - 36, W - 40, 24); label(ctx, 'Lake', W / 2, H - 24, '#0b3a45', 11);
      ctx.fillStyle = GOLD; ctx.beginPath(); ctx.arc(46, 34, 16, 0, 7); ctx.fill();
      ctx.fillStyle = '#cfd8dc'; ctx.beginPath(); ctx.arc(W - 80, 40, 22, 0, 7); ctx.arc(W - 56, 40, 26, 0, 7); ctx.arc(W - 100, 44, 18, 0, 7); ctx.fill();
      // rising vapour (left) + rain (right)
      for (var i = 0; i < 5; i++) { var yy = (H - 40) - ((t * 40 + i * 30) % (H - 70)); ctx.fillStyle = 'rgba(127,197,214,.7)'; ctx.beginPath(); ctx.arc(70 + i * 8, yy, 3, 0, 7); ctx.fill(); }
      for (var r = 0; r < 5; r++) { var ry = 60 + ((t * 90 + r * 25) % (H - 100)); ctx.strokeStyle = BLUE; ctx.beginPath(); ctx.moveTo(W - 90 + r * 12, ry); ctx.lineTo(W - 92 + r * 12, ry + 8); ctx.stroke(); }
    },
    // photosynthesis: sun -> leaf -> O2 bubbles
    photosynthesis: function (ctx, t, W, H, p) {
      ctx.fillStyle = GOLD; ctx.beginPath(); ctx.arc(40, 38, 18, 0, 7); ctx.fill();
      for (var r = 0; r < 6; r++) { var a = r * 1.05 + t; ctx.strokeStyle = GOLD; ctx.beginPath(); ctx.moveTo(40 + 22 * Math.cos(a), 38 + 22 * Math.sin(a)); ctx.lineTo(40 + 30 * Math.cos(a), 38 + 30 * Math.sin(a)); ctx.stroke(); }
      ctx.fillStyle = GREEN; ctx.beginPath(); ctx.ellipse(W / 2, H / 2 + 6, 46, 28, -0.4, 0, 7); ctx.fill();
      label(ctx, 'leaf', W / 2, H / 2 + 6, WHITE, 12);
      for (var i = 0; i < 5; i++) { var yy = (H / 2) - ((t * 40 + i * 28) % 90); ctx.fillStyle = 'rgba(39,174,96,.5)'; ctx.beginPath(); ctx.arc(W / 2 + 50 + i * 6, yy + 6, 4, 0, 7); ctx.fill(); }
      label(ctx, 'O₂ →', W - 40, H / 2 - 30, GREEN, 12);
    },
    // growing plant (agriculture)
    plantgrow: function (ctx, t, W, H, p) {
      var g = Math.min(1, (t % 5) / 3), base = H - 24, top = base - g * (H - 70), cx = W / 2;
      ctx.fillStyle = '#8d5a2b'; ctx.fillRect(cx - 40, base, 80, 12);
      ctx.strokeStyle = GREEN; ctx.lineWidth = 4; ctx.beginPath(); ctx.moveTo(cx, base); ctx.lineTo(cx, top); ctx.stroke();
      if (g > 0.4) { ctx.fillStyle = GREEN; ctx.beginPath(); ctx.ellipse(cx - 14, top + 18, 16, 8, -0.6, 0, 7); ctx.ellipse(cx + 14, top + 30, 16, 8, 0.6, 0, 7); ctx.fill(); }
      if (g > 0.9) { ctx.fillStyle = GOLD; ctx.beginPath(); ctx.arc(cx, top, 10, 0, 7); ctx.fill(); }
    },
    // pendulum (motion)
    pendulum: function (ctx, t, W, H, p) {
      var px = W / 2, py = 24, L = H - 70, ang = 0.7 * Math.sin(t * 2), bx = px + L * Math.sin(ang), by = py + L * Math.cos(ang);
      ctx.strokeStyle = SLATE; ctx.lineWidth = 2; ctx.beginPath(); ctx.moveTo(px, py); ctx.lineTo(bx, by); ctx.stroke();
      ctx.fillStyle = TEAL; ctx.beginPath(); ctx.arc(bx, by, 16, 0, 7); ctx.fill();
    },
    // planet orbiting sun
    orbit: function (ctx, t, W, H, p) {
      var cx = W / 2, cy = H / 2; ctx.fillStyle = GOLD; ctx.beginPath(); ctx.arc(cx, cy, 18, 0, 7); ctx.fill();
      ctx.strokeStyle = '#cfd8dc'; ctx.beginPath(); ctx.ellipse(cx, cy, 80, 50, 0, 0, 7); ctx.stroke();
      var a = t; ctx.fillStyle = BLUE; ctx.beginPath(); ctx.arc(cx + 80 * Math.cos(a), cy + 50 * Math.sin(a), 9, 0, 7); ctx.fill();
    }
  };
  // aliases so common topic words resolve
  var ALIAS = { motion: 'pendulum', force: 'pendulum', electricity: 'circuit', current: 'circuit', sound: 'wave', light: 'wave',
    fraction: 'pie', fractions: 'pie', percentage: 'pie', percent: 'pie', statistics: 'bargrow', data: 'bargrow', graph: 'bargrow',
    number: 'numberline', integers: 'numberline', counting: 'numberline', atom: 'atom', element: 'atom', matter: 'atom',
    ecosystem: 'watercycle', water: 'watercycle', rain: 'watercycle', plant: 'plantgrow', crop: 'plantgrow', farming: 'plantgrow',
    growth: 'plantgrow', photosynthesis: 'photosynthesis', leaf: 'photosynthesis', solar: 'orbit', earth: 'orbit' };

  function perim(x, y, w2, h2, dd) {
    if (dd < w2) return [x + dd, y];
    dd -= w2; if (dd < h2) return [x + w2, y + dd];
    dd -= h2; if (dd < w2) return [x + w2 - dd, y + h2];
    dd -= w2; return [x, y + h2 - dd];
  }

  var EireneAnim = {
    has: function (key) { return !!(SCENES[key] || ALIAS[key]); },
    resolve: function (key) { return SCENES[key] ? key : (ALIAS[key] || 'pulse'); },
    mount: function (el, anim) {
      if (!el || !anim) return;
      var key = this.resolve(anim.key || 'pulse'), scene = SCENES[key], params = anim.params || {};
      el.innerHTML = '<div class="anim-head"><span>✨ Animation</span>' +
        '<button class="btn btn-ghost btn-sm" type="button" data-act="toggle">Pause</button></div>' +
        '<canvas class="anim-canvas" width="640" height="240"></canvas>' +
        (anim.caption ? '<p class="anim-cap muted">' + anim.caption + '</p>' : '');
      var cv = el.querySelector('canvas'), ctx = cv.getContext('2d');
      var playing = true, start = null, raf = null;
      function frame(ts) {
        if (start == null) start = ts; var t = (ts - start) / 1000;
        ctx.clearRect(0, 0, cv.width, cv.height);
        try { scene(ctx, t, cv.width, cv.height, params); } catch (e) {}
        if (playing) raf = w.requestAnimationFrame(frame);
      }
      function drawStatic() { ctx.clearRect(0, 0, cv.width, cv.height); try { scene(ctx, 1.2, cv.width, cv.height, params); } catch (e) {} }
      var btn = el.querySelector('[data-act=toggle]');
      btn.addEventListener('click', function () {
        playing = !playing; btn.textContent = playing ? 'Pause' : 'Play';
        if (playing) raf = w.requestAnimationFrame(frame); else if (raf) w.cancelAnimationFrame(raf);
      });
      if (reduced) { playing = false; btn.textContent = 'Play'; drawStatic(); }
      else raf = w.requestAnimationFrame(frame);
      el._stop = function () { playing = false; if (raf) w.cancelAnimationFrame(raf); };
    }
  };
  w.EireneAnim = EireneAnim;
})(window, document);
