const { useState, useEffect, useRef } = React;

// --- GAME CONFIGURATION ---
const CANVAS_WIDTH = 400;
const CANVAS_HEIGHT = 650;
const SLIDE_ZONE_Y = 550; // Throw line
const SCALE = 0.1; // Conversion from Matter.js to Three.js

const JUICES = {
  1: { emoji: '🍓', radius: 18, color: 0xff3344, name: 'Strawberry' },
  2: { emoji: '🍊', radius: 26, color: 0xff8800, name: 'Orange' },
  3: { emoji: '🍇', radius: 36, color: 0x8833ff, name: 'Grape' },
  4: { emoji: '🍉', radius: 46, color: 0x005511, name: 'Watermelon' },
  5: { emoji: '🥥', radius: 58, color: 0x663311, name: 'Coconut' },
  6: { emoji: '🍍', radius: 72, color: 0xffdd00, name: 'Pineapple' },
  7: { emoji: '🍹', radius: 88, color: 0x00ddff, name: 'Cocktail' },
  8: { emoji: '🏆', radius: 110, color: 0xffcc00, name: 'Mega Cup' }
};

const FACES = ['🐻', '🐼', '🐰', '🐱', '🦊', '🐶', '🐯', '🐸'];

function App() {
  const [engineReady, setEngineReady] = useState(false);

  useEffect(() => {
    const loadScripts = async () => {
      const loadScript = (src) => new Promise((resolve) => {
        const script = document.createElement('script');
        script.src = src;
        script.async = true;
        script.onload = resolve;
        document.body.appendChild(script);
      });

      if (!window.Matter) await loadScript("https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js");
      if (!window.THREE) await loadScript("https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js");
      
      setEngineReady(true);
    };
    loadScripts();
  }, []);

  if (!engineReady) {
    return (
      <div className="min-h-screen bg-gradient-to-b from-sky-300 to-cyan-500 flex items-center justify-center font-bold text-white drop-shadow-md text-xl animate-pulse">
        Opening the Beach Bar...
      </div>
    );
  }

  return <Game3D />;
}

function Game3D() {
  const mountRef = useRef(null);
  
  const getNewOrder = () => Math.floor(Math.random() * 4) + 2; // Tiers 2-5
  const getRandomBaseJuice = () => Math.floor(Math.random() * 3) + 1; // Tiers 1-3

  const initialCustomers = [
    { id: 1, face: '🐻', order: getNewOrder(), slot: 0, claimed: false, hiding: false },
    { id: 2, face: '🐼', order: getNewOrder(), slot: 1, claimed: false, hiding: false },
    { id: 3, face: '🐰', order: getNewOrder(), slot: 2, claimed: false, hiding: false }
  ];

  // UI State
  const [score, setScore] = useState(0);
  const [coins, setCoins] = useState(0);
  const [nextJuice, setNextJuice] = useState(2);
  const [customersUI, setCustomersUI] = useState(initialCustomers);
  const [gameOver, setGameOver] = useState(false);

  // Game Loop State (Mutable Refs for physics sync)
  const stateRef = useRef({
    score: 0, coins: 0, current: 1, next: 2, state: 'ready', customers: initialCustomers
  });

  const refs = useRef({
    engine: null, scene: null, camera: null, renderer: null, animFrame: null,
    bodies: [], particles: [], aimMesh: null, claims: [], audioCtx: null
  });

  // --- AUDIO SYNTHESIZER ---
  const initAudio = () => {
    if (!refs.current.audioCtx) {
       refs.current.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
    }
    if (refs.current.audioCtx.state === 'suspended') {
       refs.current.audioCtx.resume();
    }
  };

  const playSFX = (type, tier = 1) => {
    const ctx = refs.current.audioCtx;
    if (!ctx) return;
    const osc = ctx.createOscillator();
    const gain = ctx.createGain();
    osc.connect(gain);
    gain.connect(ctx.destination);
    
    const now = ctx.currentTime;
    if (type === 'throw') {
        osc.type = 'sine';
        osc.frequency.setValueAtTime(300, now);
        osc.frequency.exponentialRampToValueAtTime(600, now + 0.15);
        gain.gain.setValueAtTime(0.1, now);
        gain.gain.linearRampToValueAtTime(0.01, now + 0.15);
        osc.start(now); osc.stop(now + 0.15);
    } else if (type === 'merge') {
        osc.type = 'triangle';
        osc.frequency.setValueAtTime(150 + tier * 50, now);
        gain.gain.setValueAtTime(0.15, now);
        gain.gain.exponentialRampToValueAtTime(0.01, now + 0.15);
        osc.start(now); osc.stop(now + 0.15);
    } else if (type === 'coin') {
        osc.type = 'sine';
        osc.frequency.setValueAtTime(1200, now);
        osc.frequency.setValueAtTime(1800, now + 0.05); // Ding!
        gain.gain.setValueAtTime(0.1, now);
        gain.gain.exponentialRampToValueAtTime(0.01, now + 0.3);
        osc.start(now); osc.stop(now + 0.3);
    }
  };

  useEffect(() => {
    if (!mountRef.current || !window.Matter || !window.THREE) return;

    const { Engine, Runner, Bodies, Composite, Events, Body } = window.Matter;
    const THREE = window.THREE;

    // --- 1. SETUP THREE.JS (3D VISUALS) ---
    const scene = new THREE.Scene();
    scene.background = new THREE.Color('#87CEEB');

    const camera = new THREE.PerspectiveCamera(55, CANVAS_WIDTH / CANVAS_HEIGHT, 0.1, 1000);
    camera.position.set(0, 95, 45); 
    camera.lookAt(0, 0, -10);

    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    renderer.setSize(CANVAS_WIDTH, CANVAS_HEIGHT);
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    renderer.domElement.style.width = '100%';
    renderer.domElement.style.height = 'auto';
    renderer.domElement.style.display = 'block';
    mountRef.current.appendChild(renderer.domElement);

    const ambientLight = new THREE.AmbientLight(0xffffff, 0.7);
    scene.add(ambientLight);
    
    const dirLight = new THREE.DirectionalLight(0xfff5b6, 1.2);
    dirLight.position.set(20, 60, 30);
    dirLight.castShadow = true;
    dirLight.shadow.mapSize.width = 1024;
    dirLight.shadow.mapSize.height = 1024;
    scene.add(dirLight);

    const tableMat = new THREE.MeshStandardMaterial({ color: '#e8c396', roughness: 0.8, metalness: 0.1 });
    const table = new THREE.Mesh(new THREE.BoxGeometry(CANVAS_WIDTH * SCALE, 2, CANVAS_HEIGHT * SCALE * 1.5), tableMat);
    table.position.y = -1;
    table.receiveShadow = true;
    scene.add(table);

    const wallMat = new THREE.MeshStandardMaterial({ color: '#d4a373', roughness: 0.9 });
    const wallGeoY = new THREE.BoxGeometry(1.5, 12, CANVAS_HEIGHT * SCALE * 1.5);
    const wallGeoX = new THREE.BoxGeometry(CANVAS_WIDTH * SCALE, 12, 1.5);
    
    const leftWallMesh = new THREE.Mesh(wallGeoY, wallMat);
    leftWallMesh.position.set(-(CANVAS_WIDTH / 2 * SCALE) - 0.75, 5, 0);
    const rightWallMesh = new THREE.Mesh(wallGeoY, wallMat);
    rightWallMesh.position.set((CANVAS_WIDTH / 2 * SCALE) + 0.75, 5, 0);
    
    const topWallMesh = new THREE.Mesh(wallGeoX, wallMat);
    topWallMesh.position.set(0, 5, -(CANVAS_HEIGHT / 2 * SCALE) - 0.75);
    const bottomWallMesh = new THREE.Mesh(wallGeoX, wallMat);
    bottomWallMesh.position.set(0, 5, (CANVAS_HEIGHT / 2 * SCALE) + 0.75);
    
    scene.add(leftWallMesh, rightWallMesh, topWallMesh, bottomWallMesh);

    // --- 2. SETUP MATTER.JS (2D PHYSICS) ---
    const engine = Engine.create();
    engine.world.gravity.y = -0.6; 
    engine.world.gravity.x = 0;

    const wallOpts = { isStatic: true, friction: 0, restitution: 0.4 };
    const leftWall = Bodies.rectangle(-25, CANVAS_HEIGHT / 2, 50, CANVAS_HEIGHT * 2, wallOpts);
    const rightWall = Bodies.rectangle(CANVAS_WIDTH + 25, CANVAS_HEIGHT / 2, 50, CANVAS_HEIGHT * 2, wallOpts);
    const topWall = Bodies.rectangle(CANVAS_WIDTH / 2, -25, CANVAS_WIDTH * 2, 50, { ...wallOpts, restitution: 0.2 });
    const bottomWall = Bodies.rectangle(CANVAS_WIDTH / 2, CANVAS_HEIGHT + 25, CANVAS_WIDTH * 2, 50, wallOpts);
    
    Composite.add(engine.world, [leftWall, rightWall, topWall, bottomWall]);

    refs.current.engine = engine;
    refs.current.scene = scene;
    refs.current.camera = camera;
    refs.current.renderer = renderer;

    const createFruit3D = (tier, radius) => {
      const group = new THREE.Group();
      const r = radius * SCALE;

      const matRed = new THREE.MeshStandardMaterial({ color: 0xff3344, roughness: 0.4 });
      const matOrange = new THREE.MeshStandardMaterial({ color: 0xff8800, roughness: 0.5 });
      const matPurple = new THREE.MeshStandardMaterial({ color: 0x8833ff, roughness: 0.3 });
      const matGreen = new THREE.MeshStandardMaterial({ color: 0x11aa33, roughness: 0.6 });
      const matDarkGreen = new THREE.MeshStandardMaterial({ color: 0x004411, roughness: 0.6 });
      const matBrown = new THREE.MeshStandardMaterial({ color: 0x663311, roughness: 0.8 });
      const matYellow = new THREE.MeshStandardMaterial({ color: 0xffdd00, roughness: 0.3 });
      const matCyan = new THREE.MeshStandardMaterial({ color: 0x00ccff, roughness: 0.1, transparent: true, opacity: 0.8 });
      const matGold = new THREE.MeshStandardMaterial({ color: 0xffcc00, metalness: 0.8, roughness: 0.2 });
      const matBlack = new THREE.MeshStandardMaterial({ color: 0x222222, roughness: 0.9 });

      let mesh;
      switch (tier) {
          case 1: 
              mesh = new THREE.Mesh(new THREE.SphereGeometry(r, 16, 16), matRed);
              mesh.scale.set(1, 1.2, 1);
              const sCap = new THREE.Mesh(new THREE.CylinderGeometry(r*0.8, 0, r*0.3, 6), matGreen);
              sCap.position.y = r * 1.1;
              group.add(mesh, sCap);
              break;
          case 2: 
              mesh = new THREE.Mesh(new THREE.SphereGeometry(r, 16, 16), matOrange);
              const oLeaf = new THREE.Mesh(new THREE.ConeGeometry(r*0.2, r*0.6, 4), matGreen);
              oLeaf.position.set(r*0.5, r*0.8, 0);
              oLeaf.rotation.z = -Math.PI/4;
              group.add(mesh, oLeaf);
              break;
          case 3: 
              const gGeo = new THREE.SphereGeometry(r*0.45, 16, 16);
              [[0, r*0.4, 0], [r*0.4, 0, r*0.2], [-r*0.4, 0, -r*0.2], [0, -r*0.4, r*0.4], [r*0.2, -r*0.4, -r*0.4], [-r*0.4, -r*0.2, r*0.2]].forEach(pos => {
                  const gMesh = new THREE.Mesh(gGeo, matPurple);
                  gMesh.position.set(...pos);
                  group.add(gMesh);
              });
              break;
          case 4: 
              mesh = new THREE.Mesh(new THREE.SphereGeometry(r, 16, 16), matDarkGreen);
              for(let i=0; i<3; i++) {
                  const stripe = new THREE.Mesh(new THREE.TorusGeometry(r*0.98, r*0.06, 8, 24), matGreen);
                  stripe.rotation.x = Math.PI/2;
                  stripe.rotation.y = (i * Math.PI) / 3;
                  group.add(stripe);
              }
              group.add(mesh);
              break;
          case 5: 
              mesh = new THREE.Mesh(new THREE.SphereGeometry(r, 16, 16), matBrown);
              const dotGeo = new THREE.SphereGeometry(r*0.15, 8, 8);
              [[r*0.4, r*0.5, r*0.7], [-r*0.4, r*0.5, r*0.7], [0, r*0.8, r*0.5]].forEach(pos => {
                  const dMesh = new THREE.Mesh(dotGeo, matBlack);
                  dMesh.position.set(...pos);
                  group.add(dMesh);
              });
              group.add(mesh);
              break;
          case 6: 
              mesh = new THREE.Mesh(new THREE.CylinderGeometry(r*0.8, r*0.7, r*1.6, 12), matYellow);
              const pCrown = new THREE.Mesh(new THREE.ConeGeometry(r*0.7, r*1.2, 6), matGreen);
              pCrown.position.y = r * 1.2;
              group.add(mesh, pCrown);
              break;
          case 7: 
              mesh = new THREE.Mesh(new THREE.CylinderGeometry(r*0.7, r*0.4, r*1.6, 16), matCyan);
              const straw = new THREE.Mesh(new THREE.CylinderGeometry(r*0.08, r*0.08, r*2.8, 8), matRed);
              straw.position.set(r*0.3, r*0.5, 0);
              straw.rotation.z = -Math.PI/6;
              const lemon = new THREE.Mesh(new THREE.CylinderGeometry(r*0.5, r*0.5, r*0.1, 16), matYellow);
              lemon.position.set(-r*0.6, r*0.8, 0);
              lemon.rotation.x = Math.PI/2;
              group.add(mesh, straw, lemon);
              break;
          case 8: 
              mesh = new THREE.Mesh(new THREE.CylinderGeometry(r, r*0.6, r*1.5, 16), matGold);
              mesh.position.y = r * 0.2;
              const base = new THREE.Mesh(new THREE.CylinderGeometry(r*0.7, r*0.8, r*0.4, 16), matGold);
              base.position.y = -r * 0.8;
              group.add(mesh, base);
              break;
      }

      group.traverse(child => {
          if (child.isMesh) { child.castShadow = true; child.receiveShadow = true; }
      });
      return group;
    };

    const updateAimMesh = (tier) => {
      if (refs.current.aimMesh) scene.remove(refs.current.aimMesh);
      const r = JUICES[tier].radius;
      const group = createFruit3D(tier, r);
      
      group.traverse(child => {
        if (child.isMesh) {
           child.material = child.material.clone();
           child.material.transparent = true;
           child.material.opacity = 0.6;
           child.castShadow = false; 
        }
      });

      const laserGeo = new THREE.BoxGeometry(0.3, 0.1, 150);
      const laserMat = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.5 });
      const laser = new THREE.Mesh(laserGeo, laserMat);
      laser.position.set(0, -r * SCALE + 0.2, -75);
      group.add(laser);

      scene.add(group);
      group.position.set(0, r * SCALE, (SLIDE_ZONE_Y - CANVAS_HEIGHT / 2) * SCALE);
      refs.current.aimMesh = group;
    };
    updateAimMesh(stateRef.current.current);

    const addFruit = (x, y, tier, inheritedVelocity = null) => {
      const config = JUICES[tier];
      const body = Bodies.circle(x, y, config.radius, {
        restitution: 0.3, friction: 0.1, density: 0.002 * tier, plugin: { tier }
      });
      if (inheritedVelocity) Body.setVelocity(body, inheritedVelocity);
      
      Composite.add(engine.world, body);
      const group = createFruit3D(tier, config.radius);
      scene.add(group);
      body.plugin.meshGroup = group;
    };

    const spawnParticles = (x, z, color) => {
      const pGeo = new THREE.BoxGeometry(0.8, 0.8, 0.8);
      const pMat = new THREE.MeshStandardMaterial({ color, emissive: color, emissiveIntensity: 0.5 });
      for(let i=0; i<6; i++) {
        const p = new THREE.Mesh(pGeo, pMat);
        p.position.set(x, 2, z);
        scene.add(p);
        refs.current.particles.push({
          mesh: p, vx: (Math.random() - 0.5) * 2, vy: Math.random() * 2 + 1, vz: (Math.random() - 0.5) * 2, life: 1.0
        });
      }
    };

    // --- 3. CUSTOMER CLAIM & MERGE LOGIC ---
    const flyFruitToCustomer = (tier, customer, startX, startY, startZ) => {
        const config = JUICES[tier];
        const group = createFruit3D(tier, config.radius);
        group.position.set(startX, startY, startZ);
        scene.add(group);

        refs.current.claims.push({
            mesh: group, tier: tier, customer: customer,
            x: startX, y: startY, z: startZ,
            tx: (customer.slot - 1) * 12, ty: 12, tz: -28, // Map slot 0,1,2 to 3D targets
            progress: 0
        });
    };

    Events.on(engine, 'collisionStart', (event) => {
      const bodiesToRemove = new Set();
      const bodiesToAdd = [];
      const claimsToAdd = [];

      event.pairs.forEach(({ bodyA, bodyB }) => {
        if (bodyA.isStatic || bodyB.isStatic) return;
        const tA = bodyA.plugin?.tier;
        const tB = bodyB.plugin?.tier;

        if (tA && tA === tB && !bodiesToRemove.has(bodyA) && !bodiesToRemove.has(bodyB)) {
          bodiesToRemove.add(bodyA);
          bodiesToRemove.add(bodyB);
          
          const nextTier = tA + 1;
          if (nextTier <= 8) {
            const midX = (bodyA.position.x + bodyB.position.x) / 2;
            const midY = (bodyA.position.y + bodyB.position.y) / 2;
            const speedA = Math.hypot(bodyA.velocity.x, bodyA.velocity.y);
            const speedB = Math.hypot(bodyB.velocity.x, bodyB.velocity.y);
            const inheritedVelocity = speedA > speedB ? { x: bodyA.velocity.x, y: bodyA.velocity.y } : { x: bodyB.velocity.x, y: bodyB.velocity.y };

            // See if any customer wants this newly merged fruit!
            let claimCustomer = stateRef.current.customers.find(c => !c.claimed && !c.hiding && c.order === nextTier);
            if (claimCustomer) {
                claimCustomer.claimed = true;
                setCustomersUI([...stateRef.current.customers]); // Trigger visual glow
                claimsToAdd.push({ x: midX, y: midY, tier: nextTier, customer: claimCustomer });
            } else {
                bodiesToAdd.push({ x: midX, y: midY, tier: nextTier, velocity: inheritedVelocity });
            }
          }

          stateRef.current.score += tA * 10;
          setScore(stateRef.current.score);
          playSFX('merge', tA);
        }
      });

      if (bodiesToRemove.size > 0) {
        bodiesToRemove.forEach(b => {
          Composite.remove(engine.world, b);
          scene.remove(b.plugin.meshGroup);
        });

        bodiesToAdd.forEach(b => {
          addFruit(b.x, b.y, b.tier, b.velocity);
          const px = (b.x - CANVAS_WIDTH/2) * SCALE;
          const pz = (b.y - CANVAS_HEIGHT/2) * SCALE;
          spawnParticles(px, pz, JUICES[b.tier].color);
        });

        claimsToAdd.forEach(claim => {
            const px = (claim.x - CANVAS_WIDTH/2) * SCALE;
            const pz = (claim.y - CANVAS_HEIGHT/2) * SCALE;
            const py = JUICES[claim.tier].radius * SCALE;
            flyFruitToCustomer(claim.tier, claim.customer, px, py, pz);
            spawnParticles(px, pz, JUICES[claim.tier].color);
        });
      }
    });

    // Check if resting fruits match new customers
    const checkForExistingClaims = () => {
        const bodies = Composite.allBodies(engine.world);
        for (let body of bodies) {
            if (body.isStatic || !body.plugin.meshGroup) continue;
            // If fruit is mostly resting
            if (Math.abs(body.velocity.x) < 0.2 && Math.abs(body.velocity.y) < 0.2) {
                const tier = body.plugin.tier;
                let claimCustomer = stateRef.current.customers.find(c => !c.claimed && !c.hiding && c.order === tier);
                if (claimCustomer) {
                    claimCustomer.claimed = true;
                    setCustomersUI([...stateRef.current.customers]);
                    
                    Composite.remove(engine.world, body);
                    const group = body.plugin.meshGroup;
                    scene.remove(group); // We swap it for a clean flying version
                    
                    const startX = (body.position.x - CANVAS_WIDTH / 2) * SCALE;
                    const startZ = (body.position.y - CANVAS_HEIGHT / 2) * SCALE;
                    flyFruitToCustomer(tier, claimCustomer, startX, body.circleRadius * SCALE, startZ);
                    break; // Only claim one per frame to prevent overlap bugs
                }
            }
        }
    };

    // --- 4. INPUT (Drag and Drop) ---
    let isDragging = false;
    let dragX = CANVAS_WIDTH / 2;

    const getXFromEvent = (e) => {
        const rect = renderer.domElement.getBoundingClientRect();
        const clientX = e.touches ? e.touches[0].clientX : e.clientX;
        return (clientX - rect.left) * (CANVAS_WIDTH / rect.width);
    };

    const clampX = (x) => {
        const r = JUICES[stateRef.current.current].radius;
        return Math.max(r + 5, Math.min(CANVAS_WIDTH - r - 5, x));
    };

    const handlePointerDown = (e) => {
      initAudio(); // Must initialize on interaction
      if (stateRef.current.state !== 'ready') return;
      isDragging = true;
      dragX = clampX(getXFromEvent(e));
      if (refs.current.aimMesh) refs.current.aimMesh.position.x = (dragX - CANVAS_WIDTH / 2) * SCALE;
    };

    const handlePointerMove = (e) => {
      if (!isDragging || stateRef.current.state !== 'ready') return;
      dragX = clampX(getXFromEvent(e));
      if (refs.current.aimMesh) refs.current.aimMesh.position.x = (dragX - CANVAS_WIDTH / 2) * SCALE;
    };

    const handlePointerUp = (e) => {
      if (!isDragging || stateRef.current.state !== 'ready') return;
      isDragging = false;
      playSFX('throw');

      if (refs.current.aimMesh) refs.current.aimMesh.visible = false;

      addFruit(dragX, SLIDE_ZONE_Y, stateRef.current.current);
      const bodies = Composite.allBodies(engine.world);
      const newBody = bodies[bodies.length - 1]; 
      Body.setVelocity(newBody, { x: 0, y: -16 }); 

      stateRef.current.state = 'sliding';

      setTimeout(() => {
        stateRef.current.current = stateRef.current.next;
        stateRef.current.next = getRandomBaseJuice();
        setNextJuice(stateRef.current.next);
        
        if (stateRef.current.state !== 'gameover') {
            stateRef.current.state = 'ready';
            updateAimMesh(stateRef.current.current);
        }
      }, 700);
    };

    const canvasDom = renderer.domElement;
    canvasDom.addEventListener('pointerdown', handlePointerDown);
    canvasDom.addEventListener('pointermove', handlePointerMove);
    canvasDom.addEventListener('pointerup', handlePointerUp);
    canvasDom.addEventListener('pointercancel', handlePointerUp);

    // --- 5. RENDER LOOP ---
    const runner = Runner.create();
    Runner.run(runner, engine);

    const animate = () => {
      const bodies = Composite.allBodies(engine.world);
      let isFull = false;

      bodies.forEach(body => {
        if (body.isStatic || !body.plugin.meshGroup) return;

        const x = (body.position.x - CANVAS_WIDTH / 2) * SCALE;
        const z = (body.position.y - CANVAS_HEIGHT / 2) * SCALE;
        const r = body.circleRadius * SCALE;

        const group = body.plugin.meshGroup;
        group.position.set(x, r, z);
        group.rotation.x = (body.position.y * SCALE) / r;
        group.rotation.z = -(body.position.x * SCALE) / r;

        if (body.position.y > SLIDE_ZONE_Y - 50 && Math.abs(body.velocity.y) < 0.1 && stateRef.current.state === 'ready') {
          isFull = true;
        }
      });

      checkForExistingClaims();

      // Animate Claims (Fruits flying to customers)
      for (let i = refs.current.claims.length - 1; i >= 0; i--) {
         const c = refs.current.claims[i];
         c.progress += 0.04; 
         
         c.x += (c.tx - c.x) * 0.15;
         c.y += (c.ty - c.y) * 0.15;
         c.z += (c.tz - c.z) * 0.15;
         
         c.mesh.position.set(c.x, c.y, c.z);
         c.mesh.rotation.x += 0.1;
         c.mesh.rotation.y += 0.2;

         if (c.progress >= 1) {
             scene.remove(c.mesh);
             refs.current.claims.splice(i, 1);
             
             playSFX('coin');
             spawnParticles(c.tx, c.tz, 0xffcc00); // Gold explosion!

             // Complete the transaction
             stateRef.current.score += c.customer.order * 50;
             stateRef.current.coins += c.customer.order * 10;
             setScore(stateRef.current.score);
             setCoins(stateRef.current.coins);

             // Hide customer visually
             stateRef.current.customers = stateRef.current.customers.map(cust => cust.id === c.customer.id ? { ...cust, hiding: true } : cust);
             setCustomersUI([...stateRef.current.customers]);

             // Spawn new customer after 2 seconds
             setTimeout(() => {
                 stateRef.current.customers = stateRef.current.customers.filter(cust => cust.id !== c.customer.id);
                 stateRef.current.customers.push({
                     id: Date.now(), face: FACES[Math.floor(Math.random() * FACES.length)], order: getNewOrder(), slot: c.customer.slot, claimed: false, hiding: false
                 });
                 setCustomersUI([...stateRef.current.customers]);
             }, 2000);
         }
      }

      // Update Particles
      for (let i = refs.current.particles.length - 1; i >= 0; i--) {
        const p = refs.current.particles[i];
        p.mesh.position.x += p.vx; p.mesh.position.y += p.vy; p.mesh.position.z += p.vz;
        p.vy -= 0.1; p.life -= 0.03; p.mesh.scale.setScalar(p.life);
        if (p.life <= 0) { scene.remove(p.mesh); refs.current.particles.splice(i, 1); }
      }

      if (isFull && stateRef.current.state !== 'gameover') {
        stateRef.current.state = 'gameover';
        setGameOver(true);
        if (refs.current.aimMesh) refs.current.aimMesh.visible = false;
      }

      renderer.render(scene, camera);
      refs.current.animFrame = requestAnimationFrame(animate);
    };

    animate();

    return () => {
      canvasDom.removeEventListener('pointerdown', handlePointerDown);
      canvasDom.removeEventListener('pointermove', handlePointerMove);
      canvasDom.removeEventListener('pointerup', handlePointerUp);
      canvasDom.removeEventListener('pointercancel', handlePointerUp);
      cancelAnimationFrame(refs.current.animFrame);
      Runner.stop(runner);
      Engine.clear(engine);
      mountRef.current?.removeChild(renderer.domElement);
    };
  }, []);

  const resetGame = () => {
    if (!refs.current.engine || !refs.current.scene) return;
    
    const bodies = window.Matter.Composite.allBodies(refs.current.engine.world);
    bodies.forEach(b => {
      if (!b.isStatic) {
        window.Matter.Composite.remove(refs.current.engine.world, b);
        if (b.plugin.meshGroup) refs.current.scene.remove(b.plugin.meshGroup);
      }
    });

    stateRef.current = { score: 0, coins: 0, current: 1, next: getRandomBaseJuice(), state: 'ready', customers: initialCustomers };
    setScore(0);
    setCoins(0);
    setNextJuice(stateRef.current.next);
    setCustomersUI(initialCustomers);
    setGameOver(false);
    
    if (refs.current.aimMesh) { refs.current.scene.remove(refs.current.aimMesh); refs.current.aimMesh = null; }
  };

  return (
    <div className="min-h-screen bg-gradient-to-b from-sky-300 to-cyan-500 flex flex-col items-center justify-center p-2 sm:p-4 font-sans select-none overflow-hidden touch-none">
      
      {/* Game Container */}
      <div className="w-full max-w-[420px] bg-white/40 backdrop-blur-md rounded-3xl p-3 sm:p-4 shadow-2xl relative border-2 border-white/60">
        
        {/* Header UI */}
        <div className="flex justify-between items-center mb-4 bg-white/70 rounded-2xl p-3 shadow-lg border border-white/60 z-10 relative">
          <div className="flex flex-col items-center w-1/3">
            <span className="text-pink-600 font-bold text-[10px] uppercase tracking-wider">Score</span>
            <span className="text-2xl font-black text-neutral-800">{score}</span>
          </div>
          
          <div className="flex flex-col items-center w-1/3 border-x border-white/50">
            <span className="text-yellow-600 font-bold text-[10px] uppercase tracking-wider">Coins</span>
            <div className="text-2xl font-black text-yellow-500 drop-shadow-sm flex items-center">
              <span className="text-xl mr-1">🪙</span>{coins}
            </div>
          </div>

          <div className="flex flex-col items-center w-1/3">
            <span className="text-blue-600 font-bold text-[10px] uppercase tracking-wider">Next</span>
            <div className="w-10 h-10 rounded-full bg-white/90 flex items-center justify-center border border-white shadow-inner">
               <span className="text-xl">{JUICES[nextJuice].emoji}</span>
            </div>
          </div>
        </div>

        {/* 3D Canvas Container */}
        <div className="relative rounded-2xl overflow-hidden shadow-inner border-2 border-white/60 bg-[#87CEEB]">
          
          <div ref={mountRef} className="w-full cursor-crosshair touch-none" style={{ touchAction: 'none' }} />

          {/* CUSTOMERS OVERLAY (In front of the far wall) */}
          <div className="absolute top-2 left-0 w-full flex justify-between px-6 pointer-events-none z-20">
              {[0, 1, 2].map(slot => {
                  const c = customersUI.find(cust => cust.slot === slot);
                  if (!c) return <div key={`empty-${slot}`} className="w-16" />; // Spacer
                  return (
                      <div key={c.id} className={`flex flex-col items-center transition-all duration-500 ${c.hiding ? 'opacity-0 -translate-y-4 scale-75' : 'opacity-100'}`}>
                          <div className={`bg-white/90 px-2 py-1 rounded-xl shadow-md border border-neutral-200 mb-1 transition-all ${c.claimed ? 'animate-pulse scale-110 border-green-400 bg-green-50' : 'animate-bounce'}`}>
                             <span className="text-sm">{JUICES[c.order].emoji}</span>
                          </div>
                          <div className="w-14 h-14 bg-gradient-to-br from-yellow-200 to-orange-300 rounded-full flex items-center justify-center text-3xl shadow-lg border-2 border-white relative">
                             {c.face}
                             {c.claimed && !c.hiding && (
                               <div className="absolute inset-0 rounded-full border-4 border-yellow-400 animate-ping opacity-50"></div>
                             )}
                          </div>
                      </div>
                  )
              })}
          </div>

          {/* Game Over Screen */}
          {gameOver && (
            <div className="absolute inset-0 z-50 bg-sky-900/60 flex flex-col items-center justify-center backdrop-blur-sm">
              <span className="text-6xl mb-2 animate-bounce">🍹</span>
              <h2 className="text-4xl font-black text-white drop-shadow-lg mb-6 tracking-wider">BAR FULL</h2>
              <button onClick={resetGame} className="bg-gradient-to-r from-yellow-400 to-orange-500 text-white font-black text-lg py-4 px-10 rounded-full shadow-2xl transform hover:scale-110 active:scale-95 transition-all border-2 border-white">
                Clean Table
              </button>
            </div>
          )}
        </div>
        
        <div className="mt-4 text-center">
            <span className="text-xs text-white drop-shadow-md font-bold tracking-wide">
                DRAG to aim • RELEASE to throw
            </span>
        </div>
      </div>
    </div>
  );
}


ReactDOM.createRoot(document.getElementById('root')).render(<App />);
