
import React, { useRef, useEffect } from 'react';
import { ArrowLeft, ArrowRight, ArrowUp, Megaphone } from 'lucide-react';
import { GameStatus, Player, Obstacle, Platform, Collectible, Particle, FloatingText, ObstacleType, BackgroundObject, ParallaxObject, CollectibleType, MiaCustomization, PlatformType } from '../types';
import { 
  GRAVITY, JUMP_FORCE, DOUBLE_JUMP_FORCE, GROUND_HEIGHT, MIA_WIDTH, MIA_HEIGHT,
  WEE_WIDTH_MIN, WEE_WIDTH_MAX, WEE_HEIGHT, POO_WIDTH_MIN, POO_WIDTH_MAX, 
  CAT_WIDTH, CAT_HEIGHT, BIRD_WIDTH, BIRD_HEIGHT, BIRD_SPEED, LEAF_WIDTH, LEAF_HEIGHT, LEAF_FALL_SPEED,
  ROOMBA_WIDTH, ROOMBA_HEIGHT, ROOMBA_SPEED, FLY_WIDTH, FLY_HEIGHT, FLY_SPEED,
  MAX_SPEED_BASE, ZOOMIES_SPEED_MULTIPLIER, ACCELERATION, FRICTION,
  PLATFORM_WIDTH_MIN, PLATFORM_WIDTH_MAX, OTTOMAN_HEIGHT, PLATFORM_HEIGHT, COUNTER_HEIGHT,
  SOFA_HEIGHT, FRIDGE_HEIGHT, BED_HEIGHT, BATHTUB_HEIGHT, TOILET_HEIGHT,
  CHICKEN_WIDTH, BONE_WIDTH, CHICKEN_HEIGHT, BONE_HEIGHT, STEAK_WIDTH, STEAK_HEIGHT, BISCUIT_WIDTH, BISCUIT_HEIGHT,
  COLOR_WHITE, COLOR_BONE,
  THEME_LIVING_ROOM_WALL, THEME_LIVING_ROOM_FLOOR, THEME_KITCHEN_WALL, THEME_KITCHEN_FLOOR, THEME_GARDEN_WALL, THEME_GARDEN_FLOOR,
  THEME_BEDROOM_WALL, THEME_BEDROOM_FLOOR, THEME_BATHROOM_WALL, THEME_BATHROOM_FLOOR,
  CHUNK_SIZE, BARK_COOLDOWN, BARK_DURATION, BARK_RANGE, ZOOMIES_DURATION, MAX_LIVES, INVINCIBILITY_FRAMES,
  LEVEL_SCORE_THRESHOLD, SPEED_INCREASE_PER_LEVEL, SHAKE_INTENSITY, SHAKE_DURATION,
  CAT_POUNCE_RANGE, CAT_POUNCE_VY, CAT_POUNCE_VX
} from '../constants';

// --- Sound Synthesizer ---
class SoundSynthesizer {
    ctx: AudioContext | null = null;
    bgmGain: GainNode | null = null;
    isPlayingMusic: boolean = false;
    currentNoteIndex: number = 0;
    musicInterval: number | null = null;

    constructor() {
        try {
            const AudioContextClass = window.AudioContext || (window as any).webkitAudioContext;
            this.ctx = new AudioContextClass();
        } catch (e) {
            console.error("Web Audio API not supported");
        }
    }

    resume() {
        if (this.ctx && this.ctx.state === 'suspended') {
            this.ctx.resume();
        }
    }

    playTone(freq: number, type: OscillatorType, duration: number, vol: number = 0.1) {
        if (!this.ctx) return;
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = type;
        osc.frequency.setValueAtTime(freq, this.ctx.currentTime);
        gain.gain.setValueAtTime(vol, this.ctx.currentTime);
        gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + duration);
        osc.connect(gain);
        gain.connect(this.ctx.destination);
        osc.start();
        osc.stop(this.ctx.currentTime + duration);
    }

    playJump() {
        if (!this.ctx) return;
        this.playTone(300, 'triangle', 0.1, 0.1);
    }

    playBark() {
        if (!this.ctx) return;
        this.playTone(150, 'sawtooth', 0.15, 0.1);
        setTimeout(() => this.playTone(120, 'sawtooth', 0.15, 0.1), 50);
    }

    playCollect(isRare: boolean) {
        if (!this.ctx) return;
        if (isRare) {
            this.playTone(880, 'sine', 0.1, 0.1);
            setTimeout(() => this.playTone(1100, 'sine', 0.2, 0.1), 100);
        } else {
            this.playTone(660, 'sine', 0.1, 0.05);
            setTimeout(() => this.playTone(880, 'sine', 0.1, 0.05), 50);
        }
    }

    playDamage() {
         if (!this.ctx) return;
         this.playTone(100, 'square', 0.2, 0.1);
         this.playTone(80, 'sawtooth', 0.3, 0.1);
    }

    playLevelComplete() {
        if (!this.ctx) return;
        const now = this.ctx.currentTime;
        [523.25, 659.25, 783.99, 1046.50].forEach((freq, i) => {
             const osc = this.ctx!.createOscillator();
             const gain = this.ctx!.createGain();
             osc.frequency.setValueAtTime(freq, now + i*0.1);
             gain.gain.setValueAtTime(0.1, now + i*0.1);
             gain.gain.exponentialRampToValueAtTime(0.01, now + i*0.1 + 0.5);
             osc.connect(gain);
             gain.connect(this.ctx!.destination);
             osc.start(now + i*0.1);
             osc.stop(now + i*0.1 + 0.5);
        });
    }

    startMusic(zoneIndex: number) {
        if (!this.ctx || this.isPlayingMusic) return;
        this.isPlayingMusic = true;
        this.bgmGain = this.ctx.createGain();
        this.bgmGain.gain.value = 0.08; 
        this.bgmGain.connect(this.ctx.destination);

        let notes: number[] = [];
        let speed = 300;
        let wave: OscillatorType = 'triangle';

        // 0=Living, 1=Kitchen, 2=Garden, 3=Bedroom, 4=Bathroom
        if (zoneIndex === 0) { // Living Room - Jaunty
             notes = [261, 0, 329, 0, 392, 0, 523, 392, 329, 0, 293, 0, 220, 0];
             speed = 250;
        } else if (zoneIndex === 1) { // Kitchen - Busy
             notes = [440, 440, 493, 440, 587, 0, 554, 0, 440, 0, 392, 440];
             speed = 200;
             wave = 'square';
             if(this.bgmGain) this.bgmGain.gain.value = 0.04; 
        } else if (zoneIndex === 2) { // Garden - Relaxed
             notes = [196, 0, 0, 246, 0, 293, 0, 0, 392, 0, 293, 0, 246, 0];
             speed = 400;
             wave = 'sine';
        } else if (zoneIndex === 3) { // Bedroom - Lullaby-ish
             notes = [329, 0, 392, 0, 329, 0, 261, 0, 196, 0, 0, 0];
             speed = 500;
             wave = 'sine';
        } else { // Bathroom - Echoey/Plucky
             notes = [523, 0, 659, 0, 0, 523, 0, 659, 0];
             speed = 300;
             wave = 'triangle';
        }
        
        this.musicInterval = window.setInterval(() => {
            if (!this.ctx || !this.bgmGain) return;
            const freq = notes[this.currentNoteIndex];
            if (freq > 0) {
                const osc = this.ctx.createOscillator();
                osc.type = wave;
                osc.frequency.setValueAtTime(freq, this.ctx.currentTime);
                osc.connect(this.bgmGain);
                osc.start();
                osc.stop(this.ctx.currentTime + 0.15);
            }
            this.currentNoteIndex = (this.currentNoteIndex + 1) % notes.length;
        }, speed);
    }

    stopMusic() {
        if (this.musicInterval) clearInterval(this.musicInterval);
        this.isPlayingMusic = false;
        if (this.bgmGain) {
            this.bgmGain.disconnect();
            this.bgmGain = null;
        }
    }

    updateMusicTheme(zoneIndex: number) {
        this.stopMusic();
        this.startMusic(zoneIndex);
    }
}

interface GameCanvasProps {
  gameStatus: GameStatus;
  setGameStatus: (status: GameStatus) => void;
  setScore: (score: number) => void;
  setLives: (lives: number) => void;
  canvasRef: React.RefObject<HTMLCanvasElement>;
  customization: MiaCustomization;
}

const GameCanvas: React.FC<GameCanvasProps> = ({ gameStatus, setGameStatus, setScore, setLives, canvasRef, customization }) => {
  
  const soundSystem = useRef(new SoundSynthesizer());

  const gameStateRef = useRef({
    player: {
      x: 100,
      y: 0,
      vx: 0,
      vy: 0,
      width: MIA_WIDTH,
      height: MIA_HEIGHT,
      isGrounded: true,
      jumpCount: 0,
      runFrame: 0,
      facingRight: true,
      isBarking: false,
      barkTimer: 0,
      barkCooldown: 0,
      isZoomies: false,
      zoomiesTimer: 0,
      lives: MAX_LIVES,
      maxLives: MAX_LIVES,
      invincibilityTimer: 0,
    } as Player,
    camera: { x: 0 },
    keys: { left: false, right: false, up: false, bark: false },
    obstacles: [] as Obstacle[],
    platforms: [] as Platform[],
    collectibles: [] as Collectible[],
    particles: [] as Particle[],
    floatingTexts: [] as FloatingText[],
    backgroundObjects: [] as BackgroundObject[],
    parallaxObjects: [] as ParallaxObject[],
    score: 0,
    level: 1,
    generatedUntilX: 0,
    shakeTimer: 0,
    lastTime: 0,
    animationId: 0,
    levelCompleteProcessed: false
  });

  // --- Physics Helpers ---
  const resetGame = (canvas: HTMLCanvasElement, keepLevel: boolean = false) => {
    soundSystem.current.stopMusic();
    const state = gameStateRef.current;
    
    // If we are just starting a new level, keep score and lives, but reset positions
    const newLevel = keepLevel ? state.level : 1;
    const newScore = keepLevel ? state.score : 0;
    const newLives = keepLevel ? state.player.lives : MAX_LIVES;
    const zoneIndex = (newLevel - 1) % 5;

    gameStateRef.current = {
      player: {
        x: 100,
        y: canvas.height - GROUND_HEIGHT - MIA_HEIGHT,
        vx: 0,
        vy: 0,
        width: MIA_WIDTH,
        height: MIA_HEIGHT,
        isGrounded: true,
        jumpCount: 0,
        runFrame: 0,
        facingRight: true,
        isBarking: false,
        barkTimer: 0,
        barkCooldown: 0,
        isZoomies: false,
        zoomiesTimer: 0,
        lives: newLives,
        maxLives: MAX_LIVES,
        invincibilityTimer: 0
      },
      camera: { x: 0 },
      keys: { left: false, right: false, up: false, bark: false },
      obstacles: [],
      platforms: [],
      collectibles: [],
      particles: [],
      floatingTexts: [],
      backgroundObjects: [],
      parallaxObjects: [],
      score: newScore,
      level: newLevel,
      generatedUntilX: -500, // Force generation start
      shakeTimer: 0,
      lastTime: performance.now(),
      animationId: 0,
      levelCompleteProcessed: false
    };
    
    setScore(newScore);
    setLives(newLives);
    soundSystem.current.resume();
    soundSystem.current.startMusic(zoneIndex);
  };

  const createParticles = (x: number, y: number, count: number, color: string) => {
    for (let i = 0; i < count; i++) {
      gameStateRef.current.particles.push({
        id: Math.random(),
        x,
        y,
        vx: (Math.random() - 0.5) * 8,
        vy: (Math.random() - 0.5) * 8,
        life: 1.0,
        color,
        size: Math.random() * 5 + 3,
      });
    }
  };

  const createFloatingText = (x: number, y: number, text: string, color: string) => {
    gameStateRef.current.floatingTexts.push({
      id: Math.random(),
      x,
      y,
      text,
      life: 1.0,
      color,
    });
  };

  const tryJump = () => {
    const state = gameStateRef.current;
    if (state.player.isGrounded) {
      soundSystem.current.playJump();
      state.player.vy = JUMP_FORCE;
      state.player.isGrounded = false;
      state.player.jumpCount = 1;
      createParticles(state.player.x + MIA_WIDTH/2, state.player.y + MIA_HEIGHT, 5, '#FFF');
    } else if (state.player.jumpCount < 2) {
      soundSystem.current.playJump();
      state.player.vy = DOUBLE_JUMP_FORCE;
      state.player.jumpCount++;
      createParticles(state.player.x + MIA_WIDTH/2, state.player.y + MIA_HEIGHT, 8, '#FFD700'); 
    }
  };

  const tryBark = () => {
    const state = gameStateRef.current;
    const { player } = state;
    
    if (player.barkCooldown > 0) return;
    
    soundSystem.current.playBark();
    player.isBarking = true;
    player.barkTimer = BARK_DURATION;
    player.barkCooldown = BARK_COOLDOWN;
    
    createFloatingText(player.x, player.y - 20, "WOOF!", "#FFFFFF");

    // Check for enemies in range
    const centerPlayerX = player.x + player.width/2;
    const centerPlayerY = player.y + player.height/2;

    for (let i = state.obstacles.length - 1; i >= 0; i--) {
       const obs = state.obstacles[i];
       if (obs.type.includes('cat') || obs.type === 'bird' || obs.type === 'roomba' || obs.type === 'fly') {
          const obsCenterX = obs.x + obs.width/2;
          const obsCenterY = obs.y + obs.height/2;
          const dist = Math.hypot(centerPlayerX - obsCenterX, centerPlayerY - obsCenterY);
          
          if (dist < BARK_RANGE) {
             createParticles(obsCenterX, obsCenterY, 15, '#AAAAAA');
             createFloatingText(obsCenterX, obsCenterY - 40, "SCRAM!", "#FFF");
             state.score += 200;
             setScore(state.score);
             state.obstacles.splice(i, 1);
          }
       }
    }
  };

  const getRandomCollectibleType = (): CollectibleType => {
      const r = Math.random();
      if (r > 0.94) return 'chicken'; 
      if (r > 0.85) return 'steak';   
      if (r > 0.50) return 'biscuit'; 
      return 'bone';                  
  };

  // --- World Generation ---
  const generateWorldChunk = (startX: number, endX: number, canvasHeight: number) => {
    const state = gameStateRef.current;
    
    let currentX = startX;
    
    // 0=Living, 1=Kitchen, 2=Garden, 3=Bedroom, 4=Bathroom
    const zoneIndex = (state.level - 1) % 5; 

    // --- Sky/Parallax Objects ---
    for (let px = startX; px < endX; px += 300 + Math.random() * 400) {
        if (Math.random() < 0.3) {
            state.parallaxObjects.push({
                id: Math.random(),
                x: px,
                y: Math.random() * 150,
                type: 'cloud',
                width: 150,
                height: 60,
                depth: 0.2
            });
        }
        if (zoneIndex === 2) { 
             if (Math.random() < 0.4) { 
                 state.parallaxObjects.push({
                     id: Math.random(),
                     x: px,
                     y: canvasHeight - GROUND_HEIGHT - 50,
                     type: 'hill',
                     width: 300,
                     height: 150,
                     depth: 0.5
                 });
             } else if (Math.random() < 0.4) { 
                 state.parallaxObjects.push({
                     id: Math.random(),
                     x: px,
                     y: canvasHeight - GROUND_HEIGHT - 250,
                     type: 'tree_bg',
                     width: 200,
                     height: 300,
                     depth: 0.5
                 }); 
             }
        }
    }
    
    // Background Objects (Windows, Paintings, Lamps)
    for (let bgX = startX; bgX < endX; bgX += 200 + Math.random() * 200) {
        if (zoneIndex !== 2) { // Indoor
            if (Math.random() < 0.35) {
                state.backgroundObjects.push({ 
                    id: Math.random(), x: bgX, y: 100, type: 'window', variant: 0, width: 100, height: 120 
                });
            } else if (Math.random() < 0.2) {
                 state.backgroundObjects.push({ id: Math.random(), x: bgX, y: 120, type: 'painting', variant: 0, width: 80, height: 60 });
            } else if (zoneIndex === 3 && Math.random() < 0.3) { // Bedroom lamp
                 state.backgroundObjects.push({ id: Math.random(), x: bgX, y: 140, type: 'lamp', variant: 0, width: 40, height: 80 });
            } else if (zoneIndex === 4 && Math.random() < 0.3) { // Bathroom towel
                 state.backgroundObjects.push({ id: Math.random(), x: bgX, y: 140, type: 'towel_rack', variant: 0, width: 50, height: 40 });
            }
        } else { // Garden
            if (Math.random() < 0.6) {
                state.backgroundObjects.push({
                    id: Math.random(),
                    x: bgX,
                    y: canvasHeight - GROUND_HEIGHT,
                    type: Math.random() > 0.4 ? 'tree' : 'bush',
                    variant: Math.floor(Math.random() * 3)
                });
            }
        }
    }

    while (currentX < endX) {
      currentX += 100 + Math.random() * 200;
      const roll = Math.random();
      const obstacleChance = 0.85 + (state.level * 0.02); 

      // --- Furniture Generation ---
      if (roll < 0.45) {
        const pWidth = PLATFORM_WIDTH_MIN + Math.random() * (PLATFORM_WIDTH_MAX - PLATFORM_WIDTH_MIN);
        let pHeight = 20;
        let pType: PlatformType = 'shelf';
        let pColor = '#8B0000';

        if (zoneIndex === 0) { // Living Room
            if (Math.random() > 0.5) { pType = 'sofa'; pHeight = SOFA_HEIGHT; pColor = '#8B4513'; }
            else { pType = 'books'; pHeight = 40; pColor = '#5D4037'; }
        } else if (zoneIndex === 1) { // Kitchen
            if (Math.random() > 0.7) { pType = 'fridge'; pHeight = FRIDGE_HEIGHT; pColor = '#FFF'; }
            else { pType = 'counter'; pHeight = COUNTER_HEIGHT; pColor = '#F0F0F0'; }
        } else if (zoneIndex === 2) { // Garden
             pType = 'shelf'; pHeight = 30; pColor = '#8B4513'; // Garden bench/log
        } else if (zoneIndex === 3) { // Bedroom
             if (Math.random() > 0.6) { pType = 'bed'; pHeight = BED_HEIGHT; pColor = '#F5DEB3'; }
             else { pType = 'ottoman'; pHeight = OTTOMAN_HEIGHT; pColor = '#4B0082'; }
        } else if (zoneIndex === 4) { // Bathroom
             if (Math.random() > 0.6) { pType = 'bathtub'; pHeight = BATHTUB_HEIGHT; pColor = '#FFF'; }
             else { pType = 'toilet'; pHeight = TOILET_HEIGHT; pColor = '#FFF'; }
        }

        const platY = canvasHeight - GROUND_HEIGHT - pHeight;
        state.platforms.push({
          id: Date.now() + Math.random(),
          x: currentX, y: platY, width: pWidth, height: pHeight, color: pColor, type: pType
        });

        // Add collectible on top
        if (Math.random() > 0.3) {
          const type = getRandomCollectibleType();
          const dims = (type === 'chicken') ? {w:CHICKEN_WIDTH, h:CHICKEN_HEIGHT} : (type==='steak'?{w:STEAK_WIDTH, h:STEAK_HEIGHT}:(type==='biscuit'?{w:BISCUIT_WIDTH, h:BISCUIT_HEIGHT}:{w:BONE_WIDTH, h:BONE_HEIGHT}));
          state.collectibles.push({
            id: Date.now() + Math.random(),
            x: currentX + pWidth / 2 - dims.w/2,
            y: platY - 60,
            width: dims.w, height: dims.h,
            type: type, collected: false, rotation: 0
          });
        }
        currentX += pWidth;

      } else if (roll < obstacleChance) {
        // --- Obstacle Generation ---
        const obsRoll = Math.random();
        let type: ObstacleType = 'wee';
        let vx = 0, vy = 0, w=0, h=0, y=canvasHeight-GROUND_HEIGHT;
        let initialY = 0, initialX = currentX;
        let isAsleep = false;

        // Enemies adapt to room
        if (zoneIndex === 2) { // Garden
           if (obsRoll > 0.7) type = 'leaf';
           else if (obsRoll > 0.5) type = 'bird';
           else if (obsRoll > 0.3) type = 'cat_pouncing';
           else type = 'cat_walking';
        } else { // Indoors
           if (zoneIndex === 1 && obsRoll > 0.8) type = 'roomba'; // Kitchen has roombas
           else if (obsRoll > 0.8) type = 'cat_sleeping';
           else if (obsRoll > 0.7) type = 'cat_walking';
           else if (obsRoll > 0.5) type = 'poo';
        }

        if (type === 'leaf') { w=LEAF_WIDTH; h=LEAF_HEIGHT; y=-100; vy=LEAF_FALL_SPEED + (state.level*0.2); initialY=Math.random()*100; }
        else if (type === 'bird') { w=BIRD_WIDTH; h=BIRD_HEIGHT; y=canvasHeight-GROUND_HEIGHT-60-Math.random()*100; vx=-(BIRD_SPEED + (state.level*0.2)); initialY=y; }
        else if (type === 'roomba') { w=ROOMBA_WIDTH; h=ROOMBA_HEIGHT; y=canvasHeight-GROUND_HEIGHT-h; vx=ROOMBA_SPEED+(state.level*0.3); initialX=currentX; }
        else if (type === 'wee') { w=WEE_WIDTH_MIN+Math.random()*(WEE_WIDTH_MAX-WEE_WIDTH_MIN); h=WEE_HEIGHT; y=canvasHeight-GROUND_HEIGHT-h; }
        else if (type === 'poo') { w=POO_WIDTH_MIN+Math.random()*(POO_WIDTH_MAX-POO_WIDTH_MIN); h=35; y=canvasHeight-GROUND_HEIGHT-h; }
        else if (type.includes('cat')) {
           w=CAT_WIDTH; 
           if (type === 'cat_sleeping') { h=30; isAsleep = true; } // Lower profile
           else h=CAT_HEIGHT;
           y=canvasHeight-GROUND_HEIGHT-h;
           if (type === 'cat_walking') { vx = -2; initialX = currentX; }
        }

        state.obstacles.push({
          id: Date.now() + Math.random(),
          x: currentX, y, width: w, height: h, type, vx, vy, initialY, initialX,
          patrolRange: 200 + (state.level * 20),
          swayOffset: Math.random() * Math.PI * 2,
          hasSpawnedFly: false,
          isAsleep
        });
        currentX += w;

      } else {
        // Ground Collectible
        const type = getRandomCollectibleType();
        const dims = (type === 'chicken') ? {w:CHICKEN_WIDTH, h:CHICKEN_HEIGHT} : (type==='steak'?{w:STEAK_WIDTH, h:STEAK_HEIGHT}:(type==='biscuit'?{w:BISCUIT_WIDTH, h:BISCUIT_HEIGHT}:{w:BONE_WIDTH, h:BONE_HEIGHT}));
        state.collectibles.push({
          id: Date.now() + Math.random(),
          x: currentX, y: canvasHeight - GROUND_HEIGHT - dims.h - 10,
          width: dims.w, height: dims.h,
          type: type, collected: false, rotation: 0
        });
        currentX += 40;
      }
    }
    state.generatedUntilX = endX;
  };

  // --- Drawing Functions ---

  const drawSkyLayer = (ctx: CanvasRenderingContext2D, width: number, height: number, cameraX: number, parallaxObjects: ParallaxObject[], zoneIndex: number) => {
      // Sky Color
      let skyColor = '#87CEEB';
      if (zoneIndex === 3) skyColor = '#191970'; // Midnight blue for bedroom (sleepy time)

      ctx.fillStyle = skyColor;
      ctx.fillRect(0, 0, width, height);

      // Stars for bedroom
      if (zoneIndex === 3) {
          ctx.fillStyle = '#FFF';
          for(let i=0; i<50; i++) {
              ctx.beginPath(); ctx.arc((i*100 - cameraX * 0.1) % width, (i * 37) % (height/2), 1, 0, Math.PI*2); ctx.fill();
          }
      }

      // Draw Parallax Objects (Clouds, Hills, Trees)
      parallaxObjects.forEach(obj => {
          const drawX = obj.x - (cameraX * obj.depth);
          if (drawX < -300 || drawX > width + 300) return;

          ctx.save();
          ctx.translate(drawX, obj.y);

          if (obj.type === 'cloud') {
              ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
              ctx.beginPath();
              ctx.arc(0, 0, obj.width/2, 0, Math.PI*2);
              ctx.arc(obj.width*0.4, -obj.height*0.2, obj.width/3, 0, Math.PI*2);
              ctx.arc(-obj.width*0.4, -obj.height*0.1, obj.width/3, 0, Math.PI*2);
              ctx.fill();
          } else if (obj.type === 'hill') {
              ctx.fillStyle = '#66CDAA'; 
              ctx.beginPath();
              ctx.moveTo(0, obj.height);
              ctx.quadraticCurveTo(obj.width/2, -obj.height/2, obj.width, obj.height);
              ctx.fill();
          } else if (obj.type === 'tree_bg') {
              ctx.fillStyle = '#556B2F'; 
              ctx.beginPath();
              ctx.moveTo(obj.width/2, 0);
              ctx.lineTo(obj.width, obj.height);
              ctx.lineTo(0, obj.height);
              ctx.fill();
          }
          ctx.restore();
      });
  };

  const drawMia = (ctx: CanvasRenderingContext2D, player: Player, cameraX: number, cust: MiaCustomization) => {
    const { x, y, width, height, runFrame, isGrounded, facingRight, isBarking, isZoomies, invincibilityTimer } = player;
    
    // Invincibility Flash
    if (invincibilityTimer > 0 && Math.floor(Date.now() / 100) % 2 === 0) return;

    const drawX = x - cameraX;
    
    // Zoomies Trail
    if (isZoomies) {
       for(let i=1; i<=3; i++) {
          ctx.save();
          ctx.globalAlpha = 0.3 / i;
          ctx.translate(drawX - (player.vx * i * 3) + width/2, y + height/2);
          if (!facingRight) ctx.scale(-1, 1);
          ctx.translate(-width/2, -height/2);
          ctx.fillStyle = `hsl(${Date.now()/5 % 360}, 100%, 50%)`; 
          ctx.beginPath();
          ctx.ellipse(width/2, height/2, width/2, height/2.2, 0, 0, Math.PI*2);
          ctx.fill();
          ctx.restore();
       }
    }

    ctx.save();
    
    // Bark Shockwave
    if (isBarking) {
       ctx.save();
       ctx.translate(drawX + width/2, y + height/2);
       if (!facingRight) ctx.scale(-1, 1);
       ctx.strokeStyle = `rgba(255, 255, 255, ${player.barkTimer / BARK_DURATION})`;
       ctx.lineWidth = 4;
       for(let i=1; i<=3; i++) {
           ctx.beginPath();
           ctx.arc(40, -10, 10 + (i*10) + ((BARK_DURATION - player.barkTimer)*2), -0.5, 0.5);
           ctx.stroke();
       }
       ctx.restore();
    }

    ctx.translate(drawX + width / 2, y + height / 2);
    if (!facingRight) ctx.scale(-1, 1); 
    ctx.translate(-width / 2, -height / 2);

    const bobY = isGrounded && Math.abs(player.vx) > 0.1 ? Math.sin(runFrame * 0.4) * 3 : 0;
    
    // Back Legs
    const legSpeed = Math.abs(player.vx) * 0.8;
    const lLegAngle = isGrounded ? Math.sin(runFrame * legSpeed) * 0.5 : 0.5;
    const rLegAngle = isGrounded ? Math.cos(runFrame * legSpeed) * 0.5 : -0.5;

    ctx.lineCap = 'round';
    ctx.lineJoin = 'round';
    
    // Back legs
    ctx.lineWidth = 10;
    ctx.strokeStyle = cust.furColor;
    ctx.beginPath(); ctx.moveTo(20, height*0.7+bobY); ctx.lineTo(20+Math.sin(rLegAngle)*15, height+2+bobY); ctx.stroke();
    ctx.beginPath(); ctx.moveTo(width-20, height*0.7+bobY); ctx.lineTo(width-20+Math.sin(lLegAngle)*15, height+2+bobY); ctx.stroke();

    // Tail 
    const tailWag = Math.abs(player.vx) * 2 + Math.sin(Date.now() / 50) * 8; 
    ctx.lineWidth = 6;
    ctx.strokeStyle = cust.furColor;
    ctx.beginPath();
    ctx.moveTo(5, height * 0.4 + bobY);
    ctx.quadraticCurveTo(-15, height * 0.2 + bobY, -15, height * 0.1 + bobY + tailWag);
    ctx.stroke();

    // Body 
    ctx.fillStyle = cust.furColor;
    ctx.beginPath();
    ctx.roundRect(5, 10 + bobY, width - 10, height - 20, 20);
    ctx.fill();
    
    // Shirt
    if (cust.shirt === 'vest') {
        ctx.fillStyle = '#4682B4';
        ctx.fillRect(15, 12 + bobY, width-30, height-24);
    } else if (cust.shirt === 'superhero') {
        ctx.fillStyle = '#FF0000';
        ctx.fillRect(15, 12 + bobY, width-30, height-24);
        ctx.fillStyle = 'yellow';
        ctx.beginPath(); ctx.moveTo(width/2, 20+bobY); ctx.lineTo(width/2-5, 30+bobY); ctx.lineTo(width/2+5, 30+bobY); ctx.fill();
    }

    // Zoomies Aura
    if (isZoomies) {
        ctx.strokeStyle = `hsl(${Date.now()/2 % 360}, 100%, 70%)`;
        ctx.lineWidth = 3;
        ctx.stroke();
    }

    // Collar
    ctx.fillStyle = cust.collarColor; 
    ctx.beginPath();
    ctx.rect(width * 0.65, 10 + bobY, 8, height - 20);
    ctx.fill();
    ctx.fillStyle = 'gold'; // Tag
    ctx.beginPath(); ctx.arc(width*0.69, height*0.8+bobY, 4, 0, Math.PI*2); ctx.fill();
    
    if (cust.shirt === 'bandana') {
        ctx.fillStyle = '#FF4500';
        ctx.beginPath(); ctx.moveTo(width*0.65, height*0.8+bobY); ctx.lineTo(width*0.65+10, height*0.8+bobY+15); ctx.lineTo(width*0.65-5, height*0.8+bobY+10); ctx.fill();
    }

    // Head 
    ctx.fillStyle = cust.furColor;
    ctx.beginPath();
    ctx.arc(width * 0.85, height * 0.3 + bobY, 26, 0, Math.PI * 2);
    ctx.fill();

    // Ears 
    const earBounce = player.vy * 1.5;
    ctx.fillStyle = cust.furColor;
    ctx.beginPath();
    ctx.ellipse(width * 0.75, height * 0.15 + bobY - earBounce, 12, 22, Math.PI / 4, 0, Math.PI * 2);
    ctx.fill();

    // Face 
    ctx.fillStyle = 'black'; 
    ctx.beginPath(); ctx.ellipse(width * 0.92, height * 0.25 + bobY, 5, 7, 0, 0, Math.PI * 2); ctx.fill();
    ctx.fillStyle = 'white'; 
    ctx.beginPath(); ctx.arc(width * 0.94, height * 0.22 + bobY, 2.5, 0, Math.PI * 2); ctx.fill();
    
    // Glasses
    if (cust.glasses === 'sunglasses') {
        ctx.fillStyle = 'black';
        ctx.fillRect(width*0.85, height*0.2+bobY, 20, 10);
        ctx.strokeStyle = 'black'; ctx.lineWidth=2; ctx.moveTo(width*0.85, height*0.22+bobY); ctx.lineTo(width*0.75, height*0.22+bobY); ctx.stroke();
    } else if (cust.glasses === 'nerd') {
        ctx.strokeStyle = 'black'; ctx.lineWidth = 2;
        ctx.beginPath(); ctx.arc(width*0.92, height*0.25+bobY, 8, 0, Math.PI*2); ctx.stroke();
        ctx.beginPath(); ctx.moveTo(width*0.84, height*0.25+bobY); ctx.lineTo(width*0.75, height*0.25+bobY); ctx.stroke();
    } else if (cust.glasses === '3d') {
        ctx.fillStyle = 'red'; ctx.fillRect(width*0.9, height*0.2+bobY, 8, 10);
        ctx.fillStyle = 'blue'; ctx.fillRect(width*0.82, height*0.2+bobY, 8, 10);
    }

    // Nose
    ctx.fillStyle = 'black'; 
    ctx.beginPath(); ctx.ellipse(width * 1.05, height * 0.35 + bobY, 5, 4, 0, 0, Math.PI * 2); ctx.fill();

    // Tongue 
    if (player.vx > 1) {
        ctx.fillStyle = '#FF69B4';
        ctx.beginPath();
        ctx.ellipse(width * 1.02, height * 0.5 + bobY, 6, 8, 0.5, 0, Math.PI*2);
        ctx.fill();
    }

    // Front Legs
    ctx.lineWidth = 10;
    ctx.strokeStyle = cust.furColor;
    ctx.beginPath(); ctx.moveTo(25, height*0.7+bobY); ctx.lineTo(25+Math.sin(lLegAngle)*15, height+2+bobY); ctx.stroke();
    ctx.beginPath(); ctx.moveTo(width-25, height*0.7+bobY); ctx.lineTo(width-25+Math.sin(rLegAngle)*15, height+2+bobY); ctx.stroke();

    // -- HATS --
    if (cust.hat !== 'none') {
        ctx.save();
        ctx.translate(width * 0.85, height * 0.1 + bobY);
        ctx.rotate(-0.1);
        if (cust.hat === 'party') {
            ctx.fillStyle = '#FF4500';
            ctx.beginPath(); ctx.moveTo(-15, 0); ctx.lineTo(0, -40); ctx.lineTo(15, 0); ctx.fill();
            ctx.fillStyle = 'gold'; ctx.beginPath(); ctx.arc(0, -40, 5, 0, Math.PI*2); ctx.fill();
        } else if (cust.hat === 'tophat') {
            ctx.fillStyle = '#222';
            ctx.fillRect(-20, -5, 40, 5); // Brim
            ctx.fillRect(-15, -35, 30, 30); // Top
            ctx.fillStyle = 'red'; ctx.fillRect(-15, -10, 30, 5); // Band
        } else if (cust.hat === 'bow') {
            ctx.fillStyle = '#FF1493';
            ctx.beginPath(); ctx.arc(0, 0, 5, 0, Math.PI*2); ctx.fill();
            ctx.beginPath(); ctx.moveTo(0,0); ctx.lineTo(-15, -10); ctx.lineTo(-15, 10); ctx.fill();
            ctx.beginPath(); ctx.moveTo(0,0); ctx.lineTo(15, -10); ctx.lineTo(15, 10); ctx.fill();
        } else if (cust.hat === 'cowboy') {
            ctx.fillStyle = '#8B4513';
            ctx.beginPath(); ctx.ellipse(0, 0, 30, 8, 0, 0, Math.PI*2); ctx.fill(); // Brim
            ctx.beginPath(); ctx.arc(0, -10, 15, Math.PI, 0); ctx.fill(); // Top
        } else if (cust.hat === 'crown') {
            ctx.fillStyle = 'gold';
            ctx.beginPath(); ctx.moveTo(-15, 0); ctx.lineTo(-15, -20); ctx.lineTo(-5, -10); ctx.lineTo(0, -25); ctx.lineTo(5, -10); ctx.lineTo(15, -20); ctx.lineTo(15, 0); ctx.fill();
        }
        ctx.restore();
    }

    ctx.restore();
  };

  const drawObstacle = (ctx: CanvasRenderingContext2D, obs: Obstacle, cameraX: number, playerX: number) => {
    const drawX = obs.x - cameraX;
    
    ctx.save();
    if (obs.type === 'leaf') {
        const t = Date.now() / 200 + (obs.swayOffset || 0);
        const centerX = drawX + obs.width/2;
        const centerY = obs.y + obs.height/2;
        ctx.translate(centerX, centerY);
        ctx.rotate(Math.sin(t) * 0.5);
        ctx.fillStyle = '#D2691E'; 
        ctx.beginPath(); ctx.ellipse(0, 0, obs.width/2, obs.height/2, 0, 0, Math.PI*2); ctx.fill();
        ctx.strokeStyle = '#8B4500'; ctx.beginPath(); ctx.moveTo(0, -obs.height/2); ctx.lineTo(0, obs.height/2); ctx.stroke();
    } else if (obs.type === 'fly') {
        const t = Date.now() / 50;
        const centerX = drawX + obs.width/2;
        const centerY = obs.y + obs.height/2 + Math.sin(t) * 5; 
        ctx.translate(centerX, centerY);
        ctx.scale(obs.vx && obs.vx > 0 ? -1 : 1, 1);
        ctx.fillStyle = 'rgba(200, 255, 255, 0.7)'; ctx.beginPath(); ctx.ellipse(-5, -5, 8, 4, Math.sin(t)*0.5, 0, Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.ellipse(5, -5, 8, 4, -Math.sin(t)*0.5, 0, Math.PI*2); ctx.fill();
        ctx.fillStyle = 'black'; ctx.beginPath(); ctx.ellipse(0, 0, 6, 5, 0, 0, Math.PI*2); ctx.fill();
        ctx.fillStyle = 'red'; ctx.beginPath(); ctx.arc(-3, -2, 2, 0, Math.PI*2); ctx.fill();
    } else if (obs.type === 'roomba') {
       const centerX = drawX + obs.width/2;
       const centerY = obs.y + obs.height/2;
       ctx.fillStyle = '#222'; ctx.beginPath(); ctx.ellipse(centerX, centerY + 5, obs.width/2, obs.height/2, 0, 0, Math.PI*2); ctx.fill();
       ctx.fillStyle = '#444'; ctx.beginPath(); ctx.ellipse(centerX, centerY, obs.width/2, obs.height/2, 0, 0, Math.PI*2); ctx.fill();
       const blink = Math.sin(Date.now() / 100) > 0;
       ctx.fillStyle = blink ? '#FF0000' : '#880000'; ctx.shadowColor = 'red'; ctx.shadowBlur = blink ? 10 : 0;
       ctx.beginPath(); ctx.arc(centerX, centerY - 2, 4, 0, Math.PI*2); ctx.fill(); ctx.shadowBlur = 0;
    } else if (obs.type === 'bird') {
       const centerY = obs.y + obs.height/2;
       const centerX = drawX + obs.width/2;
       const wingOffset = Math.sin(Date.now() / 80) * 10;
       ctx.fillStyle = '#111'; ctx.beginPath(); ctx.ellipse(centerX, centerY, obs.width/2, obs.height/2, 0, 0, Math.PI*2); ctx.fill();
       ctx.beginPath(); ctx.arc(centerX - obs.width/2 - 5, centerY - 5, 12, 0, Math.PI*2); ctx.fill();
       ctx.fillStyle = '#FFD700'; ctx.beginPath(); ctx.moveTo(centerX - obs.width/2 - 15, centerY - 5); ctx.lineTo(centerX - obs.width/2 - 25, centerY); ctx.lineTo(centerX - obs.width/2 - 15, centerY + 5); ctx.fill();
       ctx.fillStyle = 'white'; ctx.beginPath(); ctx.ellipse(centerX, centerY - 5, 10, 6, 0, 0, Math.PI*2); ctx.fill();
       ctx.fillStyle = '#222'; ctx.beginPath(); ctx.moveTo(centerX - 5, centerY - 5); ctx.lineTo(centerX + 20, centerY - 15 - wingOffset); ctx.lineTo(centerX + 10, centerY + 5); ctx.fill();
       ctx.fillStyle = 'white'; ctx.beginPath(); ctx.arc(centerX - obs.width/2 - 10, centerY - 8, 3, 0, Math.PI*2); ctx.fill();
       ctx.fillStyle = 'black'; ctx.beginPath(); ctx.arc(centerX - obs.width/2 - 11, centerY - 8, 1, 0, Math.PI*2); ctx.fill();
    } else if (obs.type.includes('cat')) {
      // Cat Logic & Drawing
      const distToPlayer = Math.abs(playerX - obs.x);
      const isAngry = distToPlayer < 200 && !obs.isAsleep;
      const centerX = drawX + obs.width/2;
      const bottomY = obs.y + obs.height;

      if (obs.type === 'cat_sleeping') {
          // Sleeping Cat
          ctx.fillStyle = '#1a1a1a';
          ctx.beginPath(); ctx.ellipse(centerX, bottomY - 15, 25, 15, 0, 0, Math.PI*2); ctx.fill();
          ctx.beginPath(); ctx.arc(centerX - 10, bottomY - 20, 12, 0, Math.PI*2); ctx.fill();
          // Zzz particles
          if (Math.floor(Date.now()/500) % 2 === 0) {
              ctx.fillStyle = 'white'; ctx.font = '16px Arial'; ctx.fillText('Zzz', centerX + 10, bottomY - 40);
          }
      } else {
          // Walking or Pouncing Cat with Better Legs
          const walkCycle = (Date.now() / 150) % Math.PI * 2;
          const legMove = Math.sin(walkCycle) * 10;
          
          ctx.strokeStyle = '#1a1a1a';
          ctx.lineWidth = 6;
          ctx.lineCap = 'round';
          
          // Back Legs
          ctx.beginPath(); ctx.moveTo(centerX+10, bottomY-25); ctx.lineTo(centerX+15+legMove, bottomY); ctx.stroke();
          ctx.beginPath(); ctx.moveTo(centerX-10, bottomY-25); ctx.lineTo(centerX-15-legMove, bottomY); ctx.stroke();

          // Body
          ctx.fillStyle = '#1a1a1a';
          ctx.beginPath(); ctx.ellipse(centerX, bottomY - 25, 25, 20, 0, Math.PI, 0); ctx.fill();
          
          // Front Legs
          ctx.beginPath(); ctx.moveTo(centerX+10, bottomY-25); ctx.lineTo(centerX+15-legMove, bottomY); ctx.stroke();
          ctx.beginPath(); ctx.moveTo(centerX-10, bottomY-25); ctx.lineTo(centerX-15+legMove, bottomY); ctx.stroke();

          // Head
          ctx.beginPath(); ctx.arc(centerX - 20, bottomY - 35, 15, 0, Math.PI*2); ctx.fill();
          // Ears
          ctx.beginPath(); ctx.moveTo(centerX - 30, bottomY - 45); ctx.lineTo(centerX - 35, bottomY - 60); ctx.lineTo(centerX - 20, bottomY - 48); ctx.fill();
          ctx.beginPath(); ctx.moveTo(centerX - 10, bottomY - 48); ctx.lineTo(centerX - 5, bottomY - 60); ctx.lineTo(centerX - 15, bottomY - 45); ctx.fill();
          
          // Eyes
          ctx.fillStyle = isAngry || obs.type === 'cat_pouncing' ? '#FF0000' : '#00FF00'; 
          ctx.shadowColor = ctx.fillStyle; ctx.shadowBlur = 10;
          if (isAngry || Math.floor(Date.now() / 2000) % 2 !== 0) {
             ctx.beginPath(); ctx.ellipse(centerX - 24, bottomY - 35, 3, isAngry ? 4 : 2, 0.2, 0, Math.PI*2); ctx.fill();
             ctx.beginPath(); ctx.ellipse(centerX - 16, bottomY - 35, 3, isAngry ? 4 : 2, -0.2, 0, Math.PI*2); ctx.fill();
          }
          ctx.shadowBlur = 0;

          if (obs.type === 'cat_pouncing' && obs.pounceTriggered) {
              ctx.fillStyle = 'red'; ctx.font = 'bold 20px Arial'; ctx.fillText("!!!", centerX, bottomY - 70);
          }
      }

    } else if (obs.type === 'poo') {
      ctx.fillStyle = '#3E2723';
      const piles = 4;
      const centerX = drawX + obs.width/2;
      const bottomY = obs.y + obs.height;
      for(let i=0; i<piles; i++) {
         const w = obs.width * (1 - i*0.15); const y = bottomY - (i*7) - 5; ctx.beginPath(); ctx.ellipse(centerX, y, w/2, 8, 0, 0, Math.PI*2); ctx.fill();
      }
      ctx.strokeStyle = 'rgba(100, 200, 50, 0.4)'; ctx.lineWidth = 2; const t = Date.now()/500;
      ctx.beginPath(); ctx.moveTo(centerX, bottomY - 35); ctx.quadraticCurveTo(centerX + Math.sin(t)*10, bottomY-50, centerX, bottomY-60); ctx.stroke();
      ctx.beginPath(); ctx.moveTo(centerX - 10, bottomY - 20); ctx.quadraticCurveTo(centerX - 10 + Math.sin(t + 1)*8, bottomY-40, centerX - 10, bottomY-50); ctx.stroke();
      const flyT = Date.now() / 200; ctx.fillStyle = 'black';
      for(let i=0; i<3; i++) {
          const fx = centerX + Math.cos(flyT + i*2) * 15; const fy = bottomY - 30 + Math.sin(flyT + i*2) * 10; ctx.beginPath(); ctx.arc(fx, fy, 1.5, 0, Math.PI*2); ctx.fill();
      }
    } else {
      const centerX = drawX + obs.width/2;
      const centerY = obs.y + obs.height/2;
      ctx.fillStyle = 'rgba(255, 215, 0, 0.7)'; ctx.beginPath(); ctx.ellipse(centerX, centerY, obs.width/2, obs.height/2, 0, 0, Math.PI*2); ctx.ellipse(centerX - 10, centerY + 2, obs.width/3, obs.height/2, 0.2, 0, Math.PI*2); ctx.ellipse(centerX + 15, centerY - 2, obs.width/4, obs.height/3, -0.3, 0, Math.PI*2); ctx.fill();
      ctx.fillStyle = 'rgba(255,255,200,0.6)'; const bubbleT = Date.now() / 300; ctx.beginPath(); ctx.ellipse(centerX - 10, centerY - 2, 5, 3, 0, 0, Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.ellipse(centerX + 10, centerY + 3, 4, 2, 0, 0, Math.PI*2); ctx.fill();
      ctx.fillStyle = 'rgba(255, 255, 0, 0.4)'; const floatY = (Date.now() / 20) % 50; ctx.beginPath(); ctx.arc(centerX, centerY - floatY, 2 * (1 - floatY/50), 0, Math.PI*2); ctx.fill();
    }
    ctx.restore();
  };

  const drawBackgroundObject = (ctx: CanvasRenderingContext2D, obj: BackgroundObject, cameraX: number) => {
    const drawX = obj.x - cameraX;
    
    ctx.save();
    ctx.translate(drawX, obj.y);

    if (obj.type === 'window') {
        const w = obj.width || 100;
        const h = obj.height || 100;
        ctx.fillStyle = '#FFF'; 
        ctx.fillRect(0, 0, w, h);
        ctx.strokeStyle = '#e0e0e0';
        ctx.lineWidth = 2;
        ctx.strokeRect(0, 0, w, h);
    } else if (obj.type === 'painting') {
        const w = obj.width || 80;
        const h = obj.height || 60;
        ctx.fillStyle = '#FFE4C4';
        ctx.fillRect(0, 0, w, h);
        ctx.strokeStyle = '#8B4513';
        ctx.lineWidth = 4;
        ctx.strokeRect(0, 0, w, h);
        ctx.fillStyle = 'orange'; ctx.beginPath(); ctx.arc(w/2, h/2, 10, 0, Math.PI*2); ctx.fill();
    } else if (obj.type === 'lamp') {
        ctx.fillStyle = '#FFD700'; ctx.fillRect(15, 0, 10, 80); // Stand
        ctx.fillStyle = '#FFA500'; ctx.beginPath(); ctx.moveTo(0, 20); ctx.lineTo(40, 20); ctx.lineTo(35, -10); ctx.lineTo(5, -10); ctx.fill(); // Shade
    } else if (obj.type === 'towel_rack') {
        ctx.fillStyle = 'silver'; ctx.fillRect(0, 0, 50, 5);
        ctx.fillStyle = 'pink'; ctx.fillRect(10, 5, 30, 35);
    } else if (obj.type === 'cabinet') {
        const w = obj.width || 120;
        const h = obj.height || 80;
        ctx.fillStyle = '#F5DEB3';
        ctx.fillRect(0, 0, w, h);
        ctx.strokeStyle = '#D2691E';
        ctx.strokeRect(0, 0, w, h);
        ctx.beginPath(); ctx.moveTo(w/2, 0); ctx.lineTo(w/2, h); ctx.stroke();
        ctx.fillStyle = 'silver';
        ctx.beginPath(); ctx.arc(w/2 - 10, h - 20, 4, 0, Math.PI*2); ctx.fill();
        ctx.beginPath(); ctx.arc(w/2 + 10, h - 20, 4, 0, Math.PI*2); ctx.fill();
    } else if (obj.type === 'tree') {
       ctx.fillStyle = '#8B4513';
       ctx.fillRect(-15, -150, 30, 150);
       ctx.fillStyle = obj.variant === 0 ? '#228B22' : (obj.variant === 1 ? '#006400' : '#556B2F');
       ctx.beginPath(); ctx.arc(0, -160, 60, 0, Math.PI*2); ctx.fill();
       ctx.beginPath(); ctx.arc(-40, -140, 50, 0, Math.PI*2); ctx.fill();
       ctx.beginPath(); ctx.arc(40, -140, 50, 0, Math.PI*2); ctx.fill();
    } else if (obj.type === 'bush') {
       ctx.fillStyle = obj.variant === 0 ? '#32CD32' : '#2E8B57';
       ctx.beginPath();
       ctx.arc(0, 0, 30, 0, Math.PI*2, true);
       ctx.arc(20, -10, 35, 0, Math.PI*2, true);
       ctx.arc(-20, -10, 35, 0, Math.PI*2, true);
       ctx.fill();
    } else if (obj.type === 'plant_pot') {
       ctx.fillStyle = '#CD853F';
       ctx.beginPath(); ctx.moveTo(-15, 0); ctx.lineTo(-10, -30); ctx.lineTo(10, -30); ctx.lineTo(15, 0); ctx.fill();
       ctx.fillStyle = '#228B22';
       for(let i=0; i<3; i++) {
           ctx.save(); ctx.translate(0, -25); ctx.rotate((i-1)*0.5);
           ctx.beginPath(); ctx.ellipse(0, -20, 10, 20, 0, 0, Math.PI*2); ctx.fill(); ctx.restore();
       }
    }
    ctx.restore();
  };

  const drawEnvironment = (ctx: CanvasRenderingContext2D, width: number, height: number, cameraX: number, backgroundObjects: BackgroundObject[], level: number) => {
    // 0=Living, 1=Kitchen, 2=Garden, 3=Bedroom, 4=Bathroom
    const zoneIndex = (level - 1) % 5; 

    ctx.save();
    ctx.beginPath();
    ctx.rect(0, 0, width, height - GROUND_HEIGHT);

    // Subtract windows
    backgroundObjects.forEach(obj => {
        if (obj.type === 'window') {
            const drawX = obj.x - cameraX;
            if (drawX > -100 && drawX < width + 100) {
                const w = obj.width || 100;
                const h = obj.height || 100;
                ctx.rect(drawX + 5, obj.y + 5, (w/2)-7, (h/2)-7);
                ctx.rect(drawX + (w/2)+2, obj.y + 5, (w/2)-7, (h/2)-7);
                ctx.rect(drawX + 5, obj.y + (h/2)+2, (w/2)-7, (h/2)-7);
                ctx.rect(drawX + (w/2)+2, obj.y + (h/2)+2, (w/2)-7, (h/2)-7);
            }
        }
    });
    
    ctx.clip("evenodd");

    let wallColor = THEME_LIVING_ROOM_WALL;
    if (zoneIndex === 1) wallColor = THEME_KITCHEN_WALL;
    if (zoneIndex === 2) wallColor = THEME_GARDEN_WALL;
    if (zoneIndex === 3) wallColor = THEME_BEDROOM_WALL;
    if (zoneIndex === 4) wallColor = THEME_BATHROOM_WALL;

    ctx.fillStyle = wallColor;
    ctx.fillRect(0, 0, width, height - GROUND_HEIGHT);

    // Decor Patterns
    if (zoneIndex === 0) {
        ctx.fillStyle = 'rgba(200,150,100, 0.1)';
        for(let i=0; i<width; i+=50) ctx.fillRect(i, 0, 20, height - GROUND_HEIGHT);
    } else if (zoneIndex === 1 || zoneIndex === 4) {
        ctx.strokeStyle = 'rgba(0,0,0,0.05)';
        for(let i=0; i<width; i+=50) {
            for(let j=0; j<height-GROUND_HEIGHT; j+=50) ctx.strokeRect(i, j, 50, 50);
        }
    } else if (zoneIndex === 3) {
        ctx.fillStyle = 'rgba(255,255,255,0.2)';
        for(let i=0; i<width; i+=80) ctx.beginPath(); ctx.arc(i, 100, 20, 0, Math.PI*2); ctx.fill();
    }

    ctx.restore(); 

    // Floor
    let floorColor = THEME_LIVING_ROOM_FLOOR;
    if (zoneIndex === 1) floorColor = THEME_KITCHEN_FLOOR;
    if (zoneIndex === 2) floorColor = THEME_GARDEN_FLOOR;
    if (zoneIndex === 3) floorColor = THEME_BEDROOM_FLOOR;
    if (zoneIndex === 4) floorColor = THEME_BATHROOM_FLOOR;
    
    ctx.fillStyle = floorColor;
    ctx.fillRect(0, height - GROUND_HEIGHT, width, GROUND_HEIGHT);
    
    // Fence for garden
    if (zoneIndex === 2) {
            ctx.fillStyle = '#8B4513';
            for(let i=0; i<width; i+=60) ctx.fillRect(i, height - GROUND_HEIGHT - 80, 10, 80);
    }
  };

  const drawPlatform = (ctx: CanvasRenderingContext2D, plat: Platform, cameraX: number) => {
    const drawX = plat.x - cameraX;
    
    ctx.save();
    if (plat.type === 'ottoman') {
      ctx.fillStyle = plat.color;
      ctx.beginPath(); ctx.roundRect(drawX, plat.y, plat.width, plat.height, 10); ctx.fill();
      ctx.fillStyle = 'rgba(0,0,0,0.2)';
      ctx.beginPath(); ctx.arc(drawX + plat.width*0.2, plat.y + 10, 3, 0, Math.PI*2); ctx.fill();
      ctx.beginPath(); ctx.arc(drawX + plat.width*0.8, plat.y + 10, 3, 0, Math.PI*2); ctx.fill();
      ctx.fillStyle = '#3E2723';
      ctx.fillRect(drawX + 10, plat.y + plat.height, 10, 15);
      ctx.fillRect(drawX + plat.width - 20, plat.y + plat.height, 10, 15);
    } else if (plat.type === 'counter') {
      ctx.fillStyle = '#D3D3D3'; 
      ctx.fillRect(drawX, plat.y, plat.width, 10);
      ctx.fillStyle = '#8B4513';
      ctx.fillRect(drawX + 5, plat.y + 10, plat.width - 10, plat.height - 10);
      ctx.strokeStyle = '#5D4037';
      ctx.strokeRect(drawX + 10, plat.y + 15, (plat.width/2)-15, plat.height - 20);
      ctx.fillStyle = 'silver';
      ctx.beginPath(); ctx.arc(drawX + (plat.width/2) - 5, plat.y + 30, 3, 0, Math.PI*2); ctx.fill();
    } else if (plat.type === 'sofa') {
      ctx.fillStyle = plat.color;
      // Back
      ctx.beginPath(); ctx.roundRect(drawX, plat.y, plat.width, 40, 10); ctx.fill();
      // Seat
      ctx.beginPath(); ctx.roundRect(drawX - 5, plat.y + 30, plat.width + 10, 20, 5); ctx.fill();
      // Arms
      ctx.beginPath(); ctx.roundRect(drawX - 10, plat.y + 20, 15, 30, 5); ctx.fill();
      ctx.beginPath(); ctx.roundRect(drawX + plat.width - 5, plat.y + 20, 15, 30, 5); ctx.fill();
      // Legs
      ctx.fillStyle = '#3E2723';
      ctx.fillRect(drawX, plat.y + 50, 10, 20); ctx.fillRect(drawX + plat.width - 10, plat.y + 50, 10, 20);
    } else if (plat.type === 'fridge') {
      ctx.fillStyle = 'white';
      ctx.fillRect(drawX, plat.y, plat.width, plat.height);
      ctx.fillStyle = '#EEE'; ctx.fillRect(drawX + 5, plat.y + 5, plat.width - 10, 40); // Freezer line
      ctx.fillStyle = 'silver'; ctx.fillRect(drawX + 10, plat.y + 50, 5, 40); // Handle
    } else if (plat.type === 'bed') {
      ctx.fillStyle = '#8B4513'; ctx.fillRect(drawX, plat.y + 30, plat.width, 50); // Frame
      ctx.fillStyle = 'white'; ctx.fillRect(drawX + 5, plat.y + 20, 30, 15); // Pillow
      ctx.fillStyle = '#ADD8E6'; ctx.beginPath(); ctx.roundRect(drawX, plat.y + 35, plat.width, 45, 5); ctx.fill(); // Blanket
    } else if (plat.type === 'bathtub') {
       ctx.fillStyle = 'white';
       ctx.beginPath(); ctx.roundRect(drawX, plat.y + 20, plat.width, 50, 10); ctx.fill();
       ctx.fillStyle = 'silver'; ctx.fillRect(drawX + plat.width - 20, plat.y, 5, 20); // Faucet
    } else if (plat.type === 'toilet') {
       ctx.fillStyle = 'white';
       ctx.fillRect(drawX + 10, plat.y + 20, 30, 40); // Tank
       ctx.beginPath(); ctx.arc(drawX + 50, plat.y + 40, 20, 0, Math.PI*2); ctx.fill(); // Bowl
    } else if (plat.type === 'books') {
      const colors = ['#800000', '#000080', '#006400'];
      const bookHeight = plat.height / 3;
      for(let i=0; i<3; i++) {
        ctx.fillStyle = colors[i];
        ctx.fillRect(drawX + (i*2), plat.y + (i*bookHeight), plat.width - (i*4), bookHeight);
        ctx.fillStyle = 'gold';
        ctx.fillRect(drawX + (i*2) + 5, plat.y + (i*bookHeight) + 5, plat.width - 20, 2);
      }
    } else {
      ctx.fillStyle = plat.color;
      ctx.fillRect(drawX, plat.y, plat.width, 5);
      ctx.fillRect(drawX + 10, plat.y, 5, plat.height);
      ctx.fillRect(drawX + plat.width - 15, plat.y, 5, plat.height);
    }
    ctx.restore();
  };

  const drawCollectible = (ctx: CanvasRenderingContext2D, col: Collectible, cameraX: number) => {
    const drawX = col.x - cameraX;
    const wobbleY = Math.sin(performance.now() / 200) * 5;
    
    ctx.save();
    ctx.translate(drawX + col.width/2, col.y + col.height/2 + wobbleY);
    ctx.shadowColor = col.type === 'chicken' ? "orange" : "white";
    ctx.shadowBlur = col.type === 'chicken' || col.type === 'steak' ? 15 : 0;

    if (col.type === 'chicken') {
      ctx.rotate(Math.sin(performance.now() / 500) * 0.1); 
      ctx.fillStyle = '#D2691E'; 
      ctx.beginPath(); ctx.ellipse(0, 5, 22, 16, 0, 0, Math.PI*2); ctx.fill();
      ctx.fillStyle = '#FFA07A'; ctx.beginPath(); ctx.ellipse(-5, 2, 8, 4, -0.2, 0, Math.PI*2); ctx.fill();
      ctx.fillStyle = '#D2691E'; ctx.beginPath(); ctx.ellipse(-15, -8, 8, 14, -0.6, 0, Math.PI*2); ctx.fill();
      ctx.beginPath(); ctx.ellipse(15, -8, 8, 14, 0.6, 0, Math.PI*2); ctx.fill();
      ctx.fillStyle = 'white'; ctx.beginPath(); ctx.arc(-22, -18, 4, 0, Math.PI*2); ctx.fill();
      ctx.beginPath(); ctx.arc(22, -18, 4, 0, Math.PI*2); ctx.fill();
    } else if (col.type === 'steak') {
      ctx.rotate(Math.sin(performance.now() / 600) * 0.1);
      ctx.fillStyle = '#8B0000'; ctx.beginPath(); ctx.moveTo(-20, -15); ctx.quadraticCurveTo(0, -5, 20, -15); ctx.quadraticCurveTo(25, 0, 15, 15); ctx.quadraticCurveTo(0, 20, -15, 15); ctx.quadraticCurveTo(-25, 0, -20, -15); ctx.fill();
      ctx.strokeStyle = '#E9967A'; ctx.lineWidth = 2; ctx.beginPath(); ctx.moveTo(-10, 5); ctx.quadraticCurveTo(0, 0, 10, 8); ctx.stroke();
      ctx.fillStyle = '#FFF8DC'; ctx.beginPath(); ctx.fillRect(-4, -15, 8, 20); ctx.fillRect(-15, -15, 30, 6); ctx.fill();
    } else if (col.type === 'biscuit') {
      ctx.rotate(Date.now() / 1000); 
      ctx.fillStyle = '#DEB887'; ctx.beginPath(); ctx.arc(0, 0, 12, 0, Math.PI*2); ctx.fill();
      ctx.strokeStyle = '#8B4513'; ctx.lineWidth = 2; ctx.beginPath(); ctx.arc(0, 0, 8, 0, Math.PI*2); ctx.stroke();
      ctx.fillStyle = '#8B4513'; ctx.beginPath(); ctx.arc(-4, -2, 1, 0, Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.arc(4, -2, 1, 0, Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.arc(0, 4, 1, 0, Math.PI*2); ctx.fill();
    } else {
      ctx.rotate(Date.now() / 1000); 
      ctx.fillStyle = COLOR_BONE; ctx.beginPath(); ctx.moveTo(-10, -4); ctx.lineTo(10, -4); ctx.lineTo(10, 4); ctx.lineTo(-10, 4); ctx.fill();
      ctx.beginPath(); ctx.arc(-10, -5, 5, 0, Math.PI*2); ctx.fill(); ctx.arc(-10, 5, 5, 0, Math.PI*2); ctx.fill();
      ctx.beginPath(); ctx.arc(10, -5, 5, 0, Math.PI*2); ctx.fill(); ctx.arc(10, 5, 5, 0, Math.PI*2); ctx.fill();
    }
    ctx.restore();
  };

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

    const resize = () => {
      const parent = canvas.parentElement;
      if (parent) {
        canvas.width = parent.clientWidth;
        canvas.height = parent.clientHeight;
      }
    };
    window.addEventListener('resize', resize);
    resize();

    // Logic to resume or reset
    if (gameStatus === GameStatus.PLAYING) {
        if (!gameStateRef.current.levelCompleteProcessed) {
           soundSystem.current.resume();
           // Ensure music is playing for current level
           const zoneIndex = (gameStateRef.current.level - 1) % 5;
           soundSystem.current.startMusic(zoneIndex);
        } else {
           gameStateRef.current.levelCompleteProcessed = false;
           resetGame(canvas, true); 
        }
    } else if (gameStatus === GameStatus.START_SCREEN) {
        resetGame(canvas);
        soundSystem.current.stopMusic();
    } else if (gameStatus === GameStatus.PAUSED) {
        soundSystem.current.stopMusic();
    }

    const loop = (timestamp: number) => {
      // Attractor Mode
      if (gameStatus === GameStatus.START_SCREEN || gameStatus === GameStatus.CUSTOMIZE) {
        drawSkyLayer(ctx, canvas.width, canvas.height, 0, gameStateRef.current.parallaxObjects, 0);
        drawEnvironment(ctx, canvas.width, canvas.height, 0, gameStateRef.current.backgroundObjects, 1);
        gameStateRef.current.player.y = canvas.height - GROUND_HEIGHT - MIA_HEIGHT;
        gameStateRef.current.player.x = canvas.width/2 - MIA_WIDTH/2;
        drawMia(ctx, gameStateRef.current.player, 0, customization);
        gameStateRef.current.animationId = requestAnimationFrame(loop);
        return;
      }

      if (gameStatus === GameStatus.PAUSED) {
          // Draw frozen frame (conceptually) - actually just skip update but draw once?
          // For simplicity, we just won't update physics, but we keep drawing to avoid flicker
          // Actually, let's just draw the last frame state
          const state = gameStateRef.current;
          drawSkyLayer(ctx, canvas.width, canvas.height, state.camera.x, state.parallaxObjects, (state.level - 1)%5);
          drawEnvironment(ctx, canvas.width, canvas.height, state.camera.x, state.backgroundObjects, state.level);
          state.backgroundObjects.forEach(obj => {
                if (obj.x > state.camera.x - 200 && obj.x < state.camera.x + canvas.width + 200) drawBackgroundObject(ctx, obj, state.camera.x);
          });
          state.platforms.forEach(p => { if(p.x > state.camera.x - 200 && p.x < state.camera.x + canvas.width + 200) drawPlatform(ctx, p, state.camera.x); });
          state.obstacles.forEach(o => { if(o.x > state.camera.x - 200 && o.x < state.camera.x + canvas.width + 200) drawObstacle(ctx, o, state.camera.x, state.player.x); });
          state.collectibles.forEach(c => { if(c.x > state.camera.x - 200 && c.x < state.camera.x + canvas.width + 200) drawCollectible(ctx, c, state.camera.x); });
          drawMia(ctx, state.player, state.camera.x, customization);
          
          gameStateRef.current.animationId = requestAnimationFrame(loop);
          return;
      }

      if (gameStatus === GameStatus.GAME_OVER || gameStatus === GameStatus.LEVEL_COMPLETE) return;

      const state = gameStateRef.current;
      const { player, keys } = state;

      // --- Screen Shake ---
      ctx.save();
      if (state.shakeTimer > 0) {
          const shakeX = (Math.random() - 0.5) * SHAKE_INTENSITY;
          const shakeY = (Math.random() - 0.5) * SHAKE_INTENSITY;
          ctx.translate(shakeX, shakeY);
          state.shakeTimer--;
      }

      // --- Level Complete Check ---
      if (state.score > state.level * LEVEL_SCORE_THRESHOLD) {
          state.levelCompleteProcessed = true;
          state.level++; 
          soundSystem.current.playLevelComplete();
          soundSystem.current.stopMusic();
          setGameStatus(GameStatus.LEVEL_COMPLETE);
          return; 
      }

      // --- Physics ---
      const levelSpeedBonus = (state.level - 1) * SPEED_INCREASE_PER_LEVEL;
      const baseMaxSpeed = MAX_SPEED_BASE + levelSpeedBonus;
      const currentMaxSpeed = player.isZoomies ? baseMaxSpeed * ZOOMIES_SPEED_MULTIPLIER : baseMaxSpeed;

      if (keys.left) { player.vx -= ACCELERATION; player.facingRight = false; }
      if (keys.right) { player.vx += ACCELERATION; player.facingRight = true; }

      player.vx *= FRICTION;
      if (player.vx > currentMaxSpeed) player.vx = currentMaxSpeed;
      if (player.vx < -currentMaxSpeed) player.vx = -currentMaxSpeed;
      if (Math.abs(player.vx) < 0.1) player.vx = 0;

      player.x += player.vx;
      if (Math.abs(player.vx) > 0.1) state.player.runFrame++;

      player.vy += GRAVITY;
      player.y += player.vy;

      if (player.barkTimer > 0) player.barkTimer--;
      if (player.barkCooldown > 0) player.barkCooldown--;
      if (player.barkTimer <= 0) player.isBarking = false;

      if (player.zoomiesTimer > 0) {
        player.zoomiesTimer--;
        if (player.zoomiesTimer <= 0) player.isZoomies = false;
      }

      if (player.invincibilityTimer > 0) player.invincibilityTimer--;

      // --- Collisions ---
      let landed = false;
      state.platforms.forEach(p => {
        if (
          player.vy >= 0 &&
          player.y + player.height <= p.y + player.vy + 5 &&
          player.y + player.height >= p.y - 10 &&
          player.x + player.width * 0.6 > p.x &&
          player.x + player.width * 0.4 < p.x + p.width
        ) {
          player.y = p.y - player.height;
          player.vy = 0;
          landed = true;
        }
      });

      if (!landed) {
        if (player.y + player.height >= canvas.height - GROUND_HEIGHT) {
          player.y = canvas.height - GROUND_HEIGHT - player.height;
          player.vy = 0;
          landed = true;
        }
      }
      player.isGrounded = landed;
      if (landed) player.jumpCount = 0; 

      // --- Camera ---
      const targetCamX = player.x - canvas.width * 0.3;
      state.camera.x += (targetCamX - state.camera.x) * 0.1;
      if (state.camera.x < 0) state.camera.x = 0;

      // --- World Gen ---
      if (state.camera.x + canvas.width > state.generatedUntilX - 500) {
        generateWorldChunk(state.generatedUntilX, state.generatedUntilX + CHUNK_SIZE, canvas.height);
      }

      // --- Interactions ---
      // Collectibles
      for (let i = state.collectibles.length - 1; i >= 0; i--) {
        const c = state.collectibles[i];
        if (
          !c.collected &&
          player.x < c.x + c.width &&
          player.x + player.width > c.x &&
          player.y < c.y + c.height &&
          player.y + player.height > c.y
        ) {
           c.collected = true;
           let bonus = 100;
           let label = "+100";
           let color = '#FFF';
           soundSystem.current.playCollect(c.type === 'chicken' || c.type === 'steak');

           if (c.type === 'chicken') {
              bonus = 1000; label = "ZOOMIES!"; color = '#FFA500';
              player.isZoomies = true; player.zoomiesTimer = ZOOMIES_DURATION;
           } else if (c.type === 'steak') {
              bonus = 500; label = "+1 Life!"; color = '#FF4444';
              if (player.lives < player.maxLives) { player.lives++; setLives(player.lives); }
           } else if (c.type === 'biscuit') {
              bonus = 250; label = "+250"; color = '#D2B48C';
           }

           state.score += bonus;
           setScore(state.score);
           createParticles(c.x + c.width/2, c.y + c.height/2, 10, color);
           createFloatingText(player.x, player.y - 40, label, color);
        }
        if (c.x < state.camera.x - 1000 || c.collected) state.collectibles.splice(i, 1);
      }

      // Obstacles
      for (let i = state.obstacles.length - 1; i >= 0; i--) {
        const obs = state.obstacles[i];
        if (obs.x < state.camera.x - 1000) { state.obstacles.splice(i, 1); continue; }

        // Fly Logic
        if (obs.type === 'poo' && !obs.hasSpawnedFly) {
            const dist = Math.hypot(player.x - obs.x, player.y - obs.y);
            if (dist < 300 && dist > 50) {
                if (Math.random() < 0.4) {
                    obs.hasSpawnedFly = true;
                    state.obstacles.push({
                        id: Date.now() + Math.random(),
                        x: obs.x + obs.width/2, y: obs.y, width: FLY_WIDTH, height: FLY_HEIGHT, type: 'fly', vx: 0, vy: 0
                    });
                    createParticles(obs.x + obs.width/2, obs.y, 5, 'black');
                } else { obs.hasSpawnedFly = true; }
            }
        }

        // Cat Logic
        if (obs.type === 'cat_pouncing' && !obs.pounceTriggered) {
             const dx = player.x - obs.x;
             if (Math.abs(dx) < CAT_POUNCE_RANGE && dx < 0) { // Player is to the left (approaching)
                 obs.pounceTriggered = true;
                 obs.vy = CAT_POUNCE_VY;
                 obs.vx = -CAT_POUNCE_VX; // Jump left towards player
                 createFloatingText(obs.x, obs.y - 40, "!", "#FF0000");
             }
        }

        // Physics for moving obstacles
        if (obs.type === 'leaf') {
             obs.y += obs.vy || 1; obs.x += Math.sin((Date.now() / 200) + (obs.swayOffset || 0)) * 2;
        } else if (obs.type === 'roomba' || obs.type === 'cat_walking') {
            if (obs.vx && obs.initialX !== undefined) {
                obs.x += obs.vx;
                const range = obs.patrolRange || 150;
                if (obs.x > obs.initialX + range || obs.x < obs.initialX - range) obs.vx *= -1; 
            }
        } else if (obs.type === 'fly') {
            const dx = (player.x + player.width/2) - (obs.x + obs.width/2);
            const dy = (player.y + player.height/2) - (obs.y + obs.height/2);
            const angle = Math.atan2(dy, dx);
            obs.vx = Math.cos(angle) * FLY_SPEED;
            const vy = Math.sin(angle) * FLY_SPEED;
            obs.x += obs.vx; obs.y += vy;
        } else if (obs.type === 'cat_pouncing' && obs.pounceTriggered) {
            obs.x += obs.vx || 0;
            obs.y += obs.vy || 0;
            obs.vy = (obs.vy || 0) + GRAVITY;
            if (obs.y + obs.height >= canvas.height - GROUND_HEIGHT) {
                obs.y = canvas.height - GROUND_HEIGHT - obs.height;
                obs.vy = 0; obs.vx = 0;
            }
        } else if (obs.type === 'bird') {
           obs.x += obs.vx || 0;
           obs.y = (obs.initialY || obs.y) + Math.sin(Date.now() / 200) * 30;
        }

        // Hitbox
        let padding = 8;
        if (['wee', 'poo', 'leaf', 'bird', 'roomba', 'fly'].includes(obs.type)) padding = 2;
        const px = player.x + 20; const py = player.y + 10; const pw = player.width - 40; const ph = player.height - 15; 
        
        if (px < obs.x + obs.width - padding && px + pw > obs.x + padding && py < obs.y + obs.height - padding && py + ph > obs.y + padding) {
           if (player.isZoomies) {
               createParticles(obs.x + obs.width/2, obs.y + obs.height/2, 10, '#FFF');
               createFloatingText(obs.x + obs.width/2, obs.y, "SMASH!", "#FF0000");
               state.obstacles.splice(i, 1);
               state.score += 50;
               setScore(state.score);
               soundSystem.current.playCollect(false);
           } else if (player.invincibilityTimer <= 0) {
               player.lives--;
               setLives(player.lives);
               player.invincibilityTimer = INVINCIBILITY_FRAMES;
               state.shakeTimer = SHAKE_DURATION;
               soundSystem.current.playDamage();
               
               player.vy = -6;
               player.vx = player.facingRight ? -4 : 4;
               createParticles(player.x + player.width/2, player.y + player.height/2, 10, '#FF0000');
               createFloatingText(player.x, player.y - 40, "OUCH!", "#FF0000");

               if (player.lives <= 0) {
                   soundSystem.current.stopMusic();
                   setGameStatus(GameStatus.GAME_OVER);
               }
           }
        }
    }

      // Particles & Text
      for (let i = state.particles.length - 1; i >= 0; i--) {
        const p = state.particles[i]; p.x += p.vx; p.y += p.vy; p.life -= 0.03;
        if (p.life <= 0) state.particles.splice(i, 1);
      }
      for (let i = state.floatingTexts.length - 1; i >= 0; i--) {
         const t = state.floatingTexts[i]; t.y -= 1.5; t.life -= 0.02;
         if(t.life <= 0) state.floatingTexts.splice(i, 1);
      }

      // --- Render ---
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      
      const currentZone = (state.level - 1) % 5;
      drawSkyLayer(ctx, canvas.width, canvas.height, state.camera.x, state.parallaxObjects, currentZone);

      drawEnvironment(ctx, canvas.width, canvas.height, state.camera.x, state.backgroundObjects, state.level);

      // Wall Decor & Frames
      state.backgroundObjects.forEach(obj => {
         if (obj.x > state.camera.x - 200 && obj.x < state.camera.x + canvas.width + 200) {
            drawBackgroundObject(ctx, obj, state.camera.x);
         }
      });

      // Gameplay Layer
      state.platforms.forEach(p => { if(p.x > state.camera.x - 200 && p.x < state.camera.x + canvas.width + 200) drawPlatform(ctx, p, state.camera.x); });
      state.obstacles.forEach(o => { if(o.x > state.camera.x - 200 && o.x < state.camera.x + canvas.width + 200) drawObstacle(ctx, o, state.camera.x, player.x); });
      state.collectibles.forEach(c => { if(c.x > state.camera.x - 200 && c.x < state.camera.x + canvas.width + 200) drawCollectible(ctx, c, state.camera.x); });
      
      drawMia(ctx, player, state.camera.x, customization);

      state.particles.forEach(p => { ctx.globalAlpha = p.life; ctx.fillStyle = p.color; ctx.beginPath(); ctx.arc(p.x - state.camera.x, p.y, p.size, 0, Math.PI*2); ctx.fill(); ctx.globalAlpha = 1.0; });
      state.floatingTexts.forEach(t => { ctx.globalAlpha = t.life; ctx.fillStyle = t.color; ctx.font = "bold 24px Fredoka"; ctx.strokeStyle = 'black'; ctx.lineWidth = 3; ctx.strokeText(t.text, t.x - state.camera.x, t.y); ctx.fillText(t.text, t.x - state.camera.x, t.y); ctx.globalAlpha = 1.0; });
      
      ctx.restore(); // Restore shake
      gameStateRef.current.animationId = requestAnimationFrame(loop);
    };

    const handleKeyDown = (e: KeyboardEvent) => {
       if (e.code === 'Escape' && gameStatus === GameStatus.PLAYING) setGameStatus(GameStatus.PAUSED);
       else if (e.code === 'Escape' && gameStatus === GameStatus.PAUSED) setGameStatus(GameStatus.PLAYING);

       if (gameStatus !== GameStatus.PLAYING) return;
       if (e.code === 'ArrowLeft' || e.code === 'KeyA') gameStateRef.current.keys.left = true;
       if (e.code === 'ArrowRight' || e.code === 'KeyD') gameStateRef.current.keys.right = true;
       if ((e.code === 'Space' || e.code === 'ArrowUp' || e.code === 'KeyW')) tryJump();
       if (e.code === 'KeyB' || e.code === 'Enter') tryBark();
    };

    const handleKeyUp = (e: KeyboardEvent) => {
       if (e.code === 'ArrowLeft' || e.code === 'KeyA') gameStateRef.current.keys.left = false;
       if (e.code === 'ArrowRight' || e.code === 'KeyD') gameStateRef.current.keys.right = false;
    };

    window.addEventListener('keydown', handleKeyDown);
    window.addEventListener('keyup', handleKeyUp);
    
    // Initial start logic
    if (gameStatus === GameStatus.PLAYING) {
       // Loop is started by useEffect
       gameStateRef.current.animationId = requestAnimationFrame(loop);
    } else {
       gameStateRef.current.animationId = requestAnimationFrame(loop);
    }

    return () => {
      window.removeEventListener('resize', resize);
      window.removeEventListener('keydown', handleKeyDown);
      window.removeEventListener('keyup', handleKeyUp);
      cancelAnimationFrame(gameStateRef.current.animationId);
      soundSystem.current.stopMusic();
    };
  }, [gameStatus, setGameStatus, setScore, setLives, customization]);

  return (
    <div className="relative w-full h-full select-none" onContextMenu={(e) => e.preventDefault()}>
        <canvas ref={canvasRef} className="block w-full h-full" />
        
        {/* Mobile On-Screen Controls */}
        {gameStatus === GameStatus.PLAYING && (
            <>
                <div className="absolute bottom-8 left-8 flex gap-4 z-50">
                    <button
                        className="w-20 h-20 bg-white/30 backdrop-blur-md rounded-full border-2 border-white/50 flex items-center justify-center active:bg-white/50 active:scale-95 transition-all touch-none shadow-lg"
                        onPointerDown={() => gameStateRef.current.keys.left = true}
                        onPointerUp={() => gameStateRef.current.keys.left = false}
                        onPointerLeave={() => gameStateRef.current.keys.left = false}
                    >
                        <ArrowLeft className="w-10 h-10 text-white drop-shadow-md" />
                    </button>
                    <button
                        className="w-20 h-20 bg-white/30 backdrop-blur-md rounded-full border-2 border-white/50 flex items-center justify-center active:bg-white/50 active:scale-95 transition-all touch-none shadow-lg"
                        onPointerDown={() => gameStateRef.current.keys.right = true}
                        onPointerUp={() => gameStateRef.current.keys.right = false}
                        onPointerLeave={() => gameStateRef.current.keys.right = false}
                    >
                        <ArrowRight className="w-10 h-10 text-white drop-shadow-md" />
                    </button>
                </div>

                <div className="absolute bottom-8 right-8 z-50 flex flex-col gap-4 items-end">
                    <button
                        className="w-16 h-16 bg-blue-500/50 backdrop-blur-md rounded-full border-4 border-blue-300/50 flex items-center justify-center active:bg-blue-600/60 active:scale-95 transition-all touch-none shadow-xl mb-2 mr-4"
                        onPointerDown={tryBark}
                    >
                        <Megaphone className="w-8 h-8 text-white drop-shadow-md" />
                    </button>
                    <button
                        className="w-24 h-24 bg-amber-500/40 backdrop-blur-md rounded-full border-4 border-amber-200/50 flex items-center justify-center active:bg-amber-600/60 active:scale-95 transition-all touch-none shadow-xl"
                        onPointerDown={tryJump}
                    >
                        <ArrowUp className="w-12 h-12 text-white drop-shadow-md" />
                    </button>
                </div>
            </>
        )}
    </div>
  );
};

export default GameCanvas;
