// CreatureCanvas.jsx
// Canvas-based creature animation for the Rewild Dorset illustration
// Image dimensions: 1122 × 1402px

// All region coords are relative [x, y, w, h] as fraction of image dimensions
// Pivot coords are relative [x, y] within the region

const CREATURES = [
  {
    name: 'eagle',
    region: [0.21, 0.02, 0.53, 0.25],
    pivot: [0.50, 0.80],
    anim: { type: 'bank', freq: 0.11, amplitude: 0.022 },
  },
  {
    name: 'dragonfly',
    region: [0.41, 0.00, 0.14, 0.06],
    pivot: [0.50, 0.50],
    anim: { type: 'hover', freqX: 6.3, freqY: 7.1, ampX: 1.8, ampY: 1.2 },
  },
  {
    name: 'blue_butterfly',
    region: [0.66, 0.055, 0.15, 0.065],
    pivot: [0.50, 0.50],
    anim: { type: 'wingFlutter', freq: 3.8, minScale: 0.18 },
  },
  {
    name: 'turtle_dove',
    region: [0.01, 0.08, 0.17, 0.12],
    pivot: [0.50, 0.60],
    anim: { type: 'headBob', freq: 0.45, amplitude: 0.010, bobAmt: 0.8 },
  },
  {
    name: 'bat',
    region: [0.11, 0.20, 0.22, 0.11],
    pivot: [0.50, 0.30],
    anim: { type: 'wingFlap', freq: 1.9, amplitude: 0.14 },
  },
  {
    name: 'robin',
    region: [0.78, 0.11, 0.13, 0.12],
    pivot: [0.50, 0.88],
    anim: { type: 'perchBob', freq: 1.1, amplitude: 1.2, tiltAmp: 0.012 },
  },
  {
    name: 'kingfisher',
    region: [0.79, 0.39, 0.21, 0.12],
    pivot: [0.30, 0.70],
    anim: { type: 'alertBob', freq: 0.95, amplitude: 1.4 },
  },
  {
    name: 'mice',
    region: [0.69, 0.24, 0.20, 0.10],
    pivot: [0.50, 0.80],
    anim: { type: 'sniff', freq: 1.6, amplitude: 0.6 },
  },
  {
    name: 'orange_butterfly',
    region: [0.38, 0.23, 0.14, 0.10],
    pivot: [0.50, 0.50],
    anim: { type: 'wingFlutter', freq: 4.2, minScale: 0.20 },
  },
  {
    name: 'badger',
    region: [0.02, 0.36, 0.24, 0.15],
    pivot: [0.50, 0.50],
    anim: { type: 'breathe', freq: 0.27, amplitude: 0.007 },
  },
  {
    name: 'hare',
    region: [0.01, 0.43, 0.19, 0.21],
    pivot: [0.50, 0.90],
    anim: { type: 'earTwitch', freq: 0.28, amplitude: 0.07 },
  },
  {
    name: 'otter_right',
    region: [0.57, 0.40, 0.39, 0.22],
    pivot: [0.50, 0.60],
    anim: { type: 'breatheAndSway', freq: 0.24, breatheAmp: 0.008, swayAmp: 0.008 },
  },
  {
    name: 'beaver_water',
    region: [0.19, 0.65, 0.24, 0.15],
    pivot: [0.50, 0.50],
    anim: { type: 'float', freq: 0.42, amplitude: 1.0 },
  },
  {
    name: 'bottom_beaver',
    region: [0.56, 0.59, 0.38, 0.20],
    pivot: [0.50, 0.50],
    anim: { type: 'breathe', freq: 0.21, amplitude: 0.007 },
  },
  {
    name: 'frog',
    region: [0.49, 0.77, 0.14, 0.08],
    pivot: [0.50, 0.40],
    anim: { type: 'throatPulse', freq: 0.75, amplitude: 0.018 },
  },
  {
    name: 'water_vole',
    region: [0.70, 0.53, 0.14, 0.09],
    pivot: [0.50, 0.50],
    anim: { type: 'sniff', freq: 1.9, amplitude: 0.5 },
  },
];

function computeAnim(anim, t) {
  let rotAngle = 0, scaleX = 1, scaleY = 1, transX = 0, transY = 0;
  const twoPi = Math.PI * 2;

  switch (anim.type) {
    case 'bank': {
      // Slow gliding bank — long sinusoidal rotation
      rotAngle = Math.sin(t * anim.freq * twoPi) * anim.amplitude;
      // Slight drift to feel like soaring
      transX = Math.cos(t * anim.freq * 0.7 * twoPi) * 2;
      transY = Math.sin(t * anim.freq * 0.5 * twoPi) * 1;
      break;
    }
    case 'hover': {
      // Rapid dragonfly micro-oscillation — two independent frequencies
      transX = Math.sin(t * anim.freqX * twoPi) * anim.ampX;
      transY = Math.cos(t * anim.freqY * twoPi) * anim.ampY;
      // Tiny body tilt
      rotAngle = Math.sin(t * anim.freqX * 0.4 * twoPi) * 0.04;
      break;
    }
    case 'wingFlutter': {
      // Butterfly wings opening/closing: abs(sin) gives 0→1→0 per half-period
      const openness = Math.abs(Math.sin(t * anim.freq * Math.PI));
      scaleX = anim.minScale + (1 - anim.minScale) * openness;
      // Slight vertical bob as wings beat
      transY = (1 - openness) * 1.5;
      break;
    }
    case 'headBob': {
      // Bird head bob: slow nod rotation + slight lift
      rotAngle = Math.sin(t * anim.freq * twoPi) * anim.amplitude;
      transY = Math.abs(Math.sin(t * anim.freq * Math.PI)) * (-anim.bobAmt);
      break;
    }
    case 'wingFlap': {
      // Bat wing flap — asymmetric: fast down, slow up
      const raw = Math.sin(t * anim.freq * twoPi);
      // Sharpen the downstroke
      const sharpened = Math.sign(raw) * Math.pow(Math.abs(raw), 0.7);
      rotAngle = sharpened * anim.amplitude;
      scaleY = 1 + Math.abs(sharpened) * 0.04;
      break;
    }
    case 'perchBob': {
      // Perched bird: small vertical bob + counter-tilt (pivot at feet)
      transY = Math.sin(t * anim.freq * twoPi) * anim.amplitude;
      rotAngle = Math.cos(t * anim.freq * twoPi) * anim.tiltAmp;
      break;
    }
    case 'breathe': {
      // Gentle scale breathing
      const s = 1 + Math.sin(t * anim.freq * twoPi) * anim.amplitude;
      scaleX = s;
      scaleY = s;
      break;
    }
    case 'breatheAndSway': {
      // Breathing + very slow lateral sway (otter looking around)
      const s = 1 + Math.sin(t * anim.freq * twoPi) * anim.breatheAmp;
      scaleX = s;
      scaleY = s;
      rotAngle = Math.sin(t * anim.freq * 0.6 * twoPi) * anim.swayAmp;
      break;
    }
    case 'earTwitch': {
      // Hare ear: periodic sharp flick — short attack, slow return
      const phase = (t * anim.freq) % 1.0;
      if (phase < 0.08) {
        // Sharp flick
        rotAngle = Math.sin((phase / 0.08) * Math.PI) * anim.amplitude;
      } else if (phase < 0.22) {
        // Slow drift back
        rotAngle = Math.sin(((0.22 - phase) / 0.14) * Math.PI * 0.5) * anim.amplitude * 0.25;
      }
      // Slight body sway
      transX = Math.sin(t * anim.freq * 0.5 * twoPi) * 0.4;
      break;
    }
    case 'float': {
      // Water surface float — gentle bob
      transY = Math.sin(t * anim.freq * twoPi) * anim.amplitude;
      // Tiny rocking
      rotAngle = Math.sin(t * anim.freq * 0.8 * twoPi) * 0.012;
      break;
    }
    case 'throatPulse': {
      // Frog throat: fast scale pulse on Y (throat inflating)
      const pulse = Math.abs(Math.sin(t * anim.freq * Math.PI));
      scaleY = 1 + pulse * anim.amplitude;
      scaleX = 1 - pulse * anim.amplitude * 0.3; // slight x squeeze as y expands
      break;
    }
    case 'sniff': {
      // Rodent nose sniff: tiny rapid head movement
      transY = Math.sin(t * anim.freq * twoPi) * anim.amplitude;
      transX = Math.cos(t * anim.freq * 0.6 * twoPi) * (anim.amplitude * 0.4);
      rotAngle = Math.sin(t * anim.freq * 0.3 * twoPi) * 0.008;
      break;
    }
    case 'alertBob': {
      // Kingfisher: regular bob + occasional sharp head dart
      transY = Math.sin(t * anim.freq * twoPi) * anim.amplitude;
      // Sharp downward dart every ~3s
      const dartCycle = (t * 0.33) % 1.0;
      if (dartCycle < 0.04) {
        rotAngle = Math.sin((dartCycle / 0.04) * Math.PI) * 0.08;
        transY += Math.sin((dartCycle / 0.04) * Math.PI) * 3;
      }
      break;
    }
  }
  return { rotAngle, scaleX, scaleY, transX, transY };
}

function drawCreature(ctx, img, drawX, drawY, drawW, drawH, creature, t) {
  const { region, pivot = [0.5, 0.5], anim } = creature;

  const scaleW = drawW / img.width;
  const scaleH = drawH / img.height;

  // Image-space source region
  const sx = region[0] * img.width;
  const sy = region[1] * img.height;
  const sw = region[2] * img.width;
  const sh = region[3] * img.height;

  // Canvas-space region
  const cx = drawX + sx * scaleW;
  const cy = drawY + sy * scaleH;
  const cw = sw * scaleW;
  const ch = sh * scaleH;

  // Pivot in canvas space
  const pivX = cx + pivot[0] * cw;
  const pivY = cy + pivot[1] * ch;

  const { rotAngle, scaleX, scaleY, transX, transY } = computeAnim(anim, t);

  // Padded source rect — extra coverage to hide ghost of resting position
  const PAD = 0.28;
  const padSx = Math.max(0,         sx - sw * PAD);
  const padSy = Math.max(0,         sy - sh * PAD);
  const padSr = Math.min(img.width, sx + sw + sw * PAD);
  const padSb = Math.min(img.height,sy + sh + sh * PAD);
  const padSW = padSr - padSx;
  const padSH = padSb - padSy;

  const padDx = drawX + padSx * scaleW;
  const padDy = drawY + padSy * scaleH;
  const padDW = padSW * scaleW;
  const padDH = padSH * scaleH;

  ctx.save();
  ctx.translate(pivX + transX, pivY + transY);
  ctx.rotate(rotAngle);
  ctx.scale(scaleX, scaleY);
  ctx.translate(-pivX, -pivY);
  ctx.drawImage(img, padSx, padSy, padSW, padSH, padDx, padDy, padDW, padDH);
  ctx.restore();
}

// Exported React component
const CreatureCanvas = ({ className, style }) => {
  const canvasRef = React.useRef(null);
  const rafRef    = React.useRef(null);
  const imgRef    = React.useRef(null);

  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');

    const img = new Image();
    img.src = '/assets/rewild-dorset-clean.png';
    imgRef.current = img;

    function resize() {
      canvas.width  = canvas.offsetWidth  || canvas.parentElement.offsetWidth  || 600;
      canvas.height = canvas.offsetHeight || canvas.parentElement.offsetHeight || 800;
    }

    const ro = new ResizeObserver(resize);
    ro.observe(canvas.parentElement || canvas);
    resize();

    function getDrawRect() {
      const W = canvas.width, H = canvas.height;
      const imgAspect = img.width / img.height;
      const canvasAspect = W / H;
      let drawW, drawH;
      if (canvasAspect > imgAspect) {
        drawW = W; drawH = W / imgAspect;
      } else {
        drawH = H; drawW = H * imgAspect;
      }
      return {
        W, H,
        drawX: (W - drawW) / 2,
        drawY: (H - drawH) / 2,
        drawW, drawH,
      };
    }

    let startTime = null;

    function frame(ts) {
      if (!startTime) startTime = ts;
      const t = (ts - startTime) / 1000;
      rafRef.current = requestAnimationFrame(frame);

      const { W, H, drawX, drawY, drawW, drawH } = getDrawRect();
      ctx.clearRect(0, 0, W, H);

      // — Ken Burns transform —
      const kbScale = 1 + 0.045 * (0.5 + 0.5 * Math.sin(t * 0.038));
      const kbTX = 0.022 * drawW * Math.sin(t * 0.031);
      const kbTY = 0.012 * drawH * Math.cos(t * 0.027);

      ctx.save();
      ctx.translate(W / 2 + kbTX, H / 2 + kbTY);
      ctx.scale(kbScale, kbScale);
      ctx.translate(-W / 2, -H / 2);

      // — Base image —
      ctx.drawImage(img, drawX, drawY, drawW, drawH);

      // — Creature overlays —
      if (img.complete && img.naturalWidth > 0) {
        CREATURES.forEach(c => drawCreature(ctx, img, drawX, drawY, drawW, drawH, c, t));
      }

      ctx.restore();

      // — Vignette (screen-space, no Ken Burns) —
      const grad = ctx.createRadialGradient(W/2, H/2, H*0.25, W/2, H/2, H*0.72);
      grad.addColorStop(0, 'rgba(10,24,34,0)');
      grad.addColorStop(1, 'rgba(10,24,34,0.28)');
      ctx.fillStyle = grad;
      ctx.fillRect(0, 0, W, H);

      // Bottom fade so it blends into the page
      const fade = ctx.createLinearGradient(0, H * 0.75, 0, H);
      fade.addColorStop(0, 'rgba(10,24,34,0)');
      fade.addColorStop(1, 'rgba(10,24,34,0.55)');
      ctx.fillStyle = fade;
      ctx.fillRect(0, 0, W, H);
    }

    img.onload = () => {
      resize();
      rafRef.current = requestAnimationFrame(frame);
    };

    // If already cached
    if (img.complete && img.naturalWidth > 0) {
      rafRef.current = requestAnimationFrame(frame);
    }

    return () => {
      if (rafRef.current) cancelAnimationFrame(rafRef.current);
      ro.disconnect();
    };
  }, []);

  return (
    <canvas
      ref={canvasRef}
      className={className}
      style={{ display: 'block', width: '100%', height: '100%', ...style }}
    />
  );
};

Object.assign(window, { CreatureCanvas });
