/**
 * CoinRush Plinko - Premium Casino Game
 * Matter.js Physics + React + Stake.com Style
 * 
 * Features:
 * - Realistic ball physics with gravity and bounce
 * - Provably fair ball path (server-determined)
 * - Multiple risk levels with different multipliers
 * - Dynamic row scaling (8-16 rows)
 * - WebSocket for live balance updates
 * - Full auth integration
 */

const { useState, useEffect, useRef, useCallback } = React;
const { Engine, Render, World, Bodies, Body, Events, Runner } = Matter;

// ============================================
// SVG ICONS (replacing emojis)
// ============================================
const Icons = {
  coin: () => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{width: '1em', height: '1em'}}>
      <circle cx="12" cy="12" r="10"/>
      <path d="M12 6v12M9 9h6M9 15h6"/>
    </svg>
  ),
  slotMachine: () => (
    <svg viewBox="0 0 24 24" fill="currentColor" style={{width: '1em', height: '1em'}}>
      <path d="M4 3h16a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zm2 4v10h12V7H6zm2 2h2v6H8V9zm3 0h2v6h-2V9zm3 0h2v6h-2V9z"/>
    </svg>
  ),
  volumeOn: () => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{width: '1.2em', height: '1.2em'}}>
      <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/>
      <path d="M15.54 8.46a5 5 0 0 1 0 7.07"/>
      <path d="M19.07 4.93a10 10 0 0 1 0 14.14"/>
    </svg>
  ),
  volumeOff: () => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{width: '1.2em', height: '1.2em'}}>
      <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/>
      <line x1="23" y1="9" x2="17" y2="15"/>
      <line x1="17" y1="9" x2="23" y2="15"/>
    </svg>
  ),
  check: () => (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{width: '0.9em', height: '0.9em'}}>
      <polyline points="20 6 9 17 4 12"/>
    </svg>
  )
};

// ============================================
// UTILITIES
// ============================================
const formatCoins = (cents) => {
  const coins = (cents || 0) / 100;
  return coins.toLocaleString('da-DK', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
};

const parseCoinsInput = (input) => {
  if (typeof input === 'number') return Math.round(input * 100);
  const normalized = String(input).trim().replace(/\./g, '').replace(',', '.');
  const parsed = parseFloat(normalized);
  if (!isFinite(parsed)) return 0;
  return Math.round(parsed * 100);
};

// ============================================
// MULTIPLIER TABLES FOR DIFFERENT ROWS
// ============================================
const MULTIPLIER_TABLES = {
  8: {
    low: [5.6, 2.1, 1.1, 1, 0.5, 1, 1.1, 2.1, 5.6],
    medium: [13, 3, 1.3, 0.7, 0.4, 0.7, 1.3, 3, 13],
    high: [29, 9, 2, 1.4, 0.5, 1.4, 2, 9, 29]
  },
  9: {
    low: [5.6, 2, 1.6, 1, 0.7, 0.7, 1, 1.6, 2, 5.6],
    medium: [18, 4, 1.7, 0.9, 0.5, 0.5, 0.9, 1.7, 4, 18],
    high: [43, 13, 3, 1.3, 0.7, 0.7, 1.3, 3, 13, 43]
  },
  10: {
    low: [8.9, 3, 1.4, 1.1, 1, 0.5, 1, 1.1, 1.4, 3, 8.9],
    medium: [22, 5, 2, 1.4, 0.6, 0.4, 0.6, 1.4, 2, 5, 22],
    high: [76, 10, 3, 1.5, 0.5, 0.3, 0.5, 1.5, 3, 10, 76]
  },
  11: {
    low: [8.4, 3, 1.9, 1.3, 1, 0.7, 0.7, 1, 1.3, 1.9, 3, 8.4],
    medium: [24, 6, 3, 1.8, 0.7, 0.5, 0.5, 0.7, 1.8, 3, 6, 24],
    high: [120, 14, 5.2, 1.4, 0.7, 0.4, 0.4, 0.7, 1.4, 5.2, 14, 120]
  },
  12: {
    low: [10, 3, 1.6, 1.4, 1.1, 1, 0.5, 1, 1.1, 1.4, 1.6, 3, 10],
    medium: [33, 11, 4, 2, 1.1, 0.6, 0.3, 0.6, 1.1, 2, 4, 11, 33],
    high: [170, 24, 8.1, 2, 0.7, 0.2, 0.2, 0.2, 0.7, 2, 8.1, 24, 170]
  },
  13: {
    low: [8.1, 4, 3, 1.9, 1.2, 0.9, 0.7, 0.7, 0.9, 1.2, 1.9, 3, 4, 8.1],
    medium: [43, 13, 6, 3, 1.3, 0.7, 0.4, 0.4, 0.7, 1.3, 3, 6, 13, 43],
    high: [260, 37, 11, 4, 1, 0.4, 0.2, 0.2, 0.4, 1, 4, 11, 37, 260]
  },
  14: {
    low: [7.1, 4, 1.9, 1.4, 1.3, 1.1, 1, 0.5, 1, 1.1, 1.3, 1.4, 1.9, 4, 7.1],
    medium: [58, 15, 7, 4, 1.9, 1, 0.5, 0.2, 0.5, 1, 1.9, 4, 7, 15, 58],
    high: [420, 56, 18, 5, 1.9, 0.5, 0.2, 0.2, 0.2, 0.5, 1.9, 5, 18, 56, 420]
  },
  15: {
    low: [15, 8, 3, 2, 1.5, 1.1, 1, 0.7, 0.7, 1, 1.1, 1.5, 2, 3, 8, 15],
    medium: [88, 18, 11, 5, 3, 1.3, 0.5, 0.3, 0.3, 0.5, 1.3, 3, 5, 11, 18, 88],
    high: [620, 83, 27, 8, 3, 0.5, 0.2, 0.2, 0.2, 0.2, 0.5, 3, 8, 27, 83, 620]
  },
  16: {
    low: [16, 9, 2, 1.4, 1.4, 1.2, 1.1, 1, 0.5, 1, 1.1, 1.2, 1.4, 1.4, 2, 9, 16],
    medium: [110, 41, 10, 5, 3, 1.5, 1, 0.5, 0.3, 0.5, 1, 1.5, 3, 5, 10, 41, 110],
    high: [1000, 130, 26, 9, 4, 2, 0.2, 0.2, 0.2, 0.2, 0.2, 2, 4, 9, 26, 130, 1000]
  }
};

// ============================================
// PLINKO CONFIGURATION
// ============================================
const getConfig = (rows, containerHeight = null) => {
  // Calculate dimensions to fit viewport
  // Default height calculation, but can be overridden
  const navbarHeight = 72;
  const padding = 40;
  const headerHeight = 50;
  const bucketsHeight = 40;
  
  // If container height provided, use it; otherwise calculate from viewport
  let availableHeight;
  if (containerHeight) {
    availableHeight = containerHeight - headerHeight - bucketsHeight - 20;
  } else {
    availableHeight = window.innerHeight - navbarHeight - padding - headerHeight - bucketsHeight - 40;
  }
  
  // Clamp height to reasonable bounds
  const height = Math.max(350, Math.min(550, availableHeight));
  
  // Calculate width based on aspect ratio (slightly wider than tall)
  const width = Math.min(760, height * 1.3);
  
  return {
    // Board dimensions - responsive
    CANVAS_WIDTH: width,
    CANVAS_HEIGHT: height,
    
    // Physics - tuned for realistic bouncing
    GRAVITY: 1.2,
    BALL_RADIUS: Math.max(6, Math.floor(height / 80)),
    PEG_RADIUS: Math.max(4, Math.floor(height / 120)),
    BALL_FRICTION: 0.3,
    BALL_RESTITUTION: 0.5,
    
    // Layout
    START_Y: 40,
    BUCKET_HEIGHT: 40,
    
    // Colors - Stake.com style
    COLORS: {
      background: '#0d1117',
      peg: '#1e3a5f',
      pegHit: '#00e701',
      ball: '#ff9500',
      ballGlow: 'rgba(255, 149, 0, 0.6)',
    }
  };
};

// ============================================
// PLINKO GAME COMPONENT
// ============================================
function PlinkoGame() {
  // Auth & Balance state
  const [user, setUser] = useState(null);
  const [balance, setBalance] = useState(0);
  const [wsConnected, setWsConnected] = useState(false);
  const [showAuthModal, setShowAuthModal] = useState(false);
  
  // Game state
  const [betAmount, setBetAmount] = useState(100);
  const [betDisplay, setBetDisplay] = useState('1,00');
  const [risk, setRisk] = useState('medium');
  const [rows, setRows] = useState(16);
  const [isDropping, setIsDropping] = useState(false);
  const [activeBalls, setActiveBalls] = useState(0);
  const [lastResult, setLastResult] = useState(null);
  const [showResult, setShowResult] = useState(false);
  const [soundEnabled, setSoundEnabled] = useState(true);
  const [autoMode, setAutoMode] = useState(false);
  const [autoBets, setAutoBets] = useState(0);
  const [autoRunning, setAutoRunning] = useState(false);
  
  // Persistent history - load from localStorage
  const [history, setHistory] = useState(() => {
    try {
      const saved = localStorage.getItem('plinko_history');
      return saved ? JSON.parse(saved) : [];
    } catch { return []; }
  });
  
  // Save history to localStorage whenever it changes
  useEffect(() => {
    try {
      localStorage.setItem('plinko_history', JSON.stringify(history.slice(0, 50)));
    } catch {}
  }, [history]);
  
  // Physics refs
  const canvasRef = useRef(null);
  const engineRef = useRef(null);
  const renderRef = useRef(null);
  const runnerRef = useRef(null);
  const worldRef = useRef(null);
  const configRef = useRef(getConfig(rows));
  const cleanupRef = useRef(null);
  
  // Spacebar rapid-fire refs
  const spaceHeldRef = useRef(false);
  const dropIntervalRef = useRef(null);
  const DROP_INTERVAL = 100; // ms between drops when holding spacebar
  
  // WebSocket ref
  const wsRef = useRef(null);
  
  // Get multipliers for current settings
  const multipliers = MULTIPLIER_TABLES[rows]?.[risk] || MULTIPLIER_TABLES[16][risk];
  
  // ============================================
  // WEBSOCKET CONNECTION (use shared lobby)
  // ============================================
  useEffect(() => {
    const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
    const wsUrl = `${wsProtocol}//${window.location.host}/ws/lobby`;
    
    const connect = () => {
      try {
        const socket = new WebSocket(wsUrl);
        wsRef.current = socket;
        
        socket.onopen = () => {
          setWsConnected(true);
        };
        
        socket.onmessage = (event) => {
          try {
            const data = JSON.parse(event.data);
            
            // Handle balance updates
            if (data.type === 'balance_update') {
              setBalance(data.balance);
              if (window.updateCoinRushBalance) {
                window.updateCoinRushBalance(data.balance, data.delta || null);
              }
            }
          } catch (e) {
            console.error('WebSocket message error:', e);
          }
        };
        
        socket.onclose = () => {
          setWsConnected(false);
          // Reconnect after 3 seconds
          setTimeout(connect, 3000);
        };
        
        socket.onerror = () => {
          setWsConnected(false);
        };
      } catch (e) {
        console.error('WebSocket connection error:', e);
        setWsConnected(false);
      }
    };
    
    connect();
    
    return () => {
      if (wsRef.current) {
        wsRef.current.close();
      }
    };
  }, []);
  
  // ============================================
  // FETCH USER DATA
  // ============================================
  useEffect(() => {
    fetchUserData();
    
    // Listen for auth changes
    const handleAuthChange = () => fetchUserData();
    window.addEventListener('coinrush:auth', handleAuthChange);
    window.addEventListener('coinrush:balance', (e) => {
      if (e.detail?.balance !== undefined) {
        setBalance(e.detail.balance);
      }
    });
    
    return () => {
      window.removeEventListener('coinrush:auth', handleAuthChange);
    };
  }, []);
  
  const fetchUserData = async () => {
    try {
      // Use credentials: include to send cookies (same as other pages)
      const res = await fetch('/me', {
        credentials: 'include'
      });
      
      if (res.ok) {
        const data = await res.json();
        setUser(data);
        setBalance(data.balance || 0);
      } else {
        setUser(null);
        setBalance(0);
      }
    } catch (err) {
      console.error('Failed to fetch user:', err);
      setUser(null);
      setBalance(0);
    }
  };
  
  // ============================================
  // INITIALIZE/REBUILD PHYSICS ENGINE
  // ============================================
  const initPhysics = useCallback(() => {
    if (!canvasRef.current) return;
    
    // Cleanup previous engine
    if (cleanupRef.current) {
      cleanupRef.current();
    }
    
    const config = getConfig(rows);
    configRef.current = config;
    
    // Create engine
    const engine = Engine.create({
      gravity: { x: 0, y: config.GRAVITY }
    });
    engineRef.current = engine;
    worldRef.current = engine.world;
    
    // Create renderer
    const render = Render.create({
      canvas: canvasRef.current,
      engine: engine,
      options: {
        width: config.CANVAS_WIDTH,
        height: config.CANVAS_HEIGHT,
        wireframes: false,
        background: config.COLORS.background,
        pixelRatio: Math.min(window.devicePixelRatio, 2)
      }
    });
    renderRef.current = render;
    
    // Create runner
    const runner = Runner.create();
    runnerRef.current = runner;
    
    // Build the board
    buildBoard(engine, config);
    
    // Collision detection
    const collisionHandler = (event) => handleCollision(event, config);
    Events.on(engine, 'collisionStart', collisionHandler);
    
    // After each physics update, gently guide balls toward their target
    const afterUpdateHandler = () => {
      const bodies = engine.world.bodies;
      bodies.forEach(body => {
        if (body.label === 'ball' && !body.hasLanded && body.targetX !== undefined) {
          const ballX = body.position.x;
          const ballY = body.position.y;
          const targetX = body.targetX;
          
          // How far down? (0 = top, 1 = bottom)
          const progress = Math.max(0, (ballY - config.START_Y) / (config.CANVAS_HEIGHT - config.START_Y - config.BUCKET_HEIGHT));
          
          // Error from target
          const error = targetX - ballX;
          
          // Apply gentle corrective force - stronger near the bottom
          const strength = 0.00003 * (1 + progress * 3);
          const correction = Math.sign(error) * Math.min(Math.abs(error) * strength, 0.0005);
          
          Body.applyForce(body, body.position, { x: correction, y: 0 });
          
          // Keep ball in bounds
          if (ballX < 30) {
            Body.setPosition(body, { x: 30, y: ballY });
            Body.setVelocity(body, { x: Math.abs(body.velocity.x) * 0.5, y: body.velocity.y });
          }
          if (ballX > config.CANVAS_WIDTH - 30) {
            Body.setPosition(body, { x: config.CANVAS_WIDTH - 30, y: ballY });
            Body.setVelocity(body, { x: -Math.abs(body.velocity.x) * 0.5, y: body.velocity.y });
          }
        }
      });
    };
    Events.on(engine, 'afterUpdate', afterUpdateHandler);
    
    // Start
    Render.run(render);
    Runner.run(runner, engine);
    
    // Store cleanup function
    cleanupRef.current = () => {
      Events.off(engine, 'collisionStart', collisionHandler);
      Events.off(engine, 'afterUpdate', afterUpdateHandler);
      Render.stop(render);
      Runner.stop(runner);
      World.clear(engine.world);
      Engine.clear(engine);
    };
  }, [rows, risk]);
  
  useEffect(() => {
    initPhysics();
    return () => {
      if (cleanupRef.current) {
        cleanupRef.current();
      }
    };
  }, [initPhysics]);
  
  // ============================================
  // BUILD PLINKO BOARD
  // ============================================
  const buildBoard = (engine, config) => {
    const bodies = [];
    const numBuckets = rows + 1;
    
    // Calculate layout
    const boardPadding = 40;
    const availableWidth = config.CANVAS_WIDTH - boardPadding * 2;
    const bucketWidth = availableWidth / numBuckets;
    
    // Peg area
    const pegAreaTop = config.START_Y;
    const pegAreaBottom = config.CANVAS_HEIGHT - config.BUCKET_HEIGHT - 20;
    const pegAreaHeight = pegAreaBottom - pegAreaTop;
    const rowSpacing = pegAreaHeight / rows;
    
    // Create pegs in pyramid pattern
    // The bottom row has (rows + 2) pegs, top row has 3 pegs
    for (let row = 0; row < rows; row++) {
      const pegsInRow = row + 3;
      const rowWidth = (pegsInRow - 1) * bucketWidth;
      const startX = (config.CANVAS_WIDTH - rowWidth) / 2;
      const y = pegAreaTop + row * rowSpacing;
      
      for (let col = 0; col < pegsInRow; col++) {
        const x = startX + col * bucketWidth;
        
        const peg = Bodies.circle(x, y, config.PEG_RADIUS, {
          isStatic: true,
          restitution: 0.6,
          friction: 0.0,
          label: 'peg',
          render: {
            fillStyle: config.COLORS.peg
          }
        });
        bodies.push(peg);
      }
    }
    
    // Create bucket area at bottom
    const bucketY = config.CANVAS_HEIGHT - config.BUCKET_HEIGHT / 2;
    const bucketStartX = (config.CANVAS_WIDTH - availableWidth) / 2;
    
    // Bucket dividers
    for (let i = 0; i <= numBuckets; i++) {
      const x = bucketStartX + i * bucketWidth;
      const divider = Bodies.rectangle(x, bucketY, 4, config.BUCKET_HEIGHT, {
        isStatic: true,
        label: 'divider',
        render: { fillStyle: '#1a1f2e' }
      });
      bodies.push(divider);
    }
    
    // Bucket floors (sensors for detection)
    for (let i = 0; i < numBuckets; i++) {
      const x = bucketStartX + (i + 0.5) * bucketWidth;
      const floor = Bodies.rectangle(x, config.CANVAS_HEIGHT - 8, bucketWidth - 8, 12, {
        isStatic: true,
        label: `bucket_${i}`,
        isSensor: true,
        render: { 
          fillStyle: getBucketColorForIndex(i, numBuckets),
          opacity: 0.9
        }
      });
      bodies.push(floor);
    }
    
    // Side walls - solid walls to keep ball in bounds
    const wallThickness = 40;
    bodies.push(
      // Left wall - extends beyond canvas
      Bodies.rectangle(-wallThickness / 2 + 10, config.CANVAS_HEIGHT / 2, wallThickness, config.CANVAS_HEIGHT + 100, {
        isStatic: true,
        restitution: 0.5,
        label: 'wall',
        render: { visible: false }
      }),
      // Right wall - extends beyond canvas
      Bodies.rectangle(config.CANVAS_WIDTH + wallThickness / 2 - 10, config.CANVAS_HEIGHT / 2, wallThickness, config.CANVAS_HEIGHT + 100, {
        isStatic: true,
        restitution: 0.5,
        label: 'wall',
        render: { visible: false }
      }),
      // Bottom - catches any balls
      Bodies.rectangle(config.CANVAS_WIDTH / 2, config.CANVAS_HEIGHT + 20, config.CANVAS_WIDTH + 100, 40, {
        isStatic: true,
        label: 'floor',
        render: { visible: false }
      })
    );
    
    World.add(engine.world, bodies);
  };
  
  // Helper to get bucket color based on multiplier
  const getBucketColorForIndex = (index, total) => {
    const mult = multipliers[index] || 1;
    if (mult >= 100) return '#ff0055';
    if (mult >= 50) return '#ff2266';
    if (mult >= 20) return '#ff4477';
    if (mult >= 10) return '#ff6644';
    if (mult >= 5) return '#ff8833';
    if (mult >= 2) return '#ffaa22';
    if (mult >= 1) return '#cccc00';
    if (mult >= 0.5) return '#66bb66';
    return '#44aa44';
  };
  
  // ============================================
  // HANDLE COLLISION - Simple and reliable
  // ============================================
  const handleCollision = (event, config) => {
    event.pairs.forEach(pair => {
      const { bodyA, bodyB } = pair;
      
      // Ball hit bucket
      if (bodyA.label?.startsWith('bucket_') || bodyB.label?.startsWith('bucket_')) {
        const ballBody = bodyA.label === 'ball' ? bodyA : (bodyB.label === 'ball' ? bodyB : null);
        
        if (ballBody && !ballBody.hasLanded) {
          ballBody.hasLanded = true;
          // Use the SERVER-determined bucket for correct payout
          onBallLand(ballBody, ballBody.targetBucket);
          
          // Remove ball after a short delay
          setTimeout(() => {
            if (engineRef.current) {
              World.remove(engineRef.current.world, ballBody);
            }
          }, 500);
        }
      }
      
      // Ball hit floor (fallback if misses bucket)
      if ((bodyA.label === 'floor' || bodyB.label === 'floor')) {
        const ballBody = bodyA.label === 'ball' ? bodyA : (bodyB.label === 'ball' ? bodyB : null);
        
        if (ballBody && !ballBody.hasLanded) {
          ballBody.hasLanded = true;
          onBallLand(ballBody, ballBody.targetBucket);
          
          setTimeout(() => {
            if (engineRef.current) {
              World.remove(engineRef.current.world, ballBody);
            }
          }, 300);
        }
      }
      
      // Peg hit - just flash, no physics manipulation
      if ((bodyA.label === 'peg' || bodyB.label === 'peg') &&
          (bodyA.label === 'ball' || bodyB.label === 'ball')) {
        const pegBody = bodyA.label === 'peg' ? bodyA : bodyB;
        
        if (soundEnabled) playPegSound();
        
        // Flash peg green
        const originalColor = pegBody.render.fillStyle;
        pegBody.render.fillStyle = config.COLORS.pegHit;
        setTimeout(() => {
          pegBody.render.fillStyle = originalColor;
        }, 100);
      }
    });
  };
  
  // ============================================
  // ON BALL LAND
  // ============================================
  const onBallLand = (ball, bucketIndex) => {
    const mult = multipliers[bucketIndex] || 1;
    const payout = Math.floor(ball.betAmount * mult);
    const profit = payout - ball.betAmount;
    const isWin = profit > 0;
    const isBigWin = mult >= 5;
    
    setLastResult({
      bucketIndex,
      multiplier: mult,
      payout,
      profit,
      isWin
    });
    
    setHistory(prev => [{
      multiplier: mult,
      isWin,
      timestamp: Date.now()
    }, ...prev.slice(0, 49)]); // Keep 50 entries
    
    // Update balance from server response stored on ball
    if (ball.serverBalance !== undefined) {
      setBalance(ball.serverBalance);
      if (window.updateCoinRushBalance) {
        const delta = payout - ball.betAmount;
        window.updateCoinRushBalance(ball.serverBalance, isWin ? delta : null);
      }
    }
    
    setShowResult(true);
    setTimeout(() => setShowResult(false), 1500);
    
    if (soundEnabled) {
      if (isBigWin) {
        playBigWinSound();
      } else if (isWin) {
        playWinSound();
      } else {
        playLoseSound();
      }
    }
    
    // Remove ball
    setTimeout(() => {
      if (engineRef.current) {
        World.remove(engineRef.current.world, ball);
        setActiveBalls(prev => Math.max(0, prev - 1));
      }
      setIsDropping(false);
    }, 300);
  };
  
  // ============================================
  // DROP BALL - Allows up to 30 concurrent balls
  // ============================================
  const MAX_BALLS = 30;
  
  const dropBall = async () => {
    if (!user) {
      setShowAuthModal(true);
      return;
    }
    
    if (betAmount < 100) {
      return; // Silently ignore - don't alert during rapid fire
    }
    
    if (betAmount > balance) {
      return; // Silently ignore - don't alert during rapid fire
    }
    
    // Allow multiple balls, up to MAX_BALLS
    if (activeBalls >= MAX_BALLS) {
      return; // Silently ignore if too many balls
    }
    
    try {
      const res = await fetch('/api/plinko/drop', {
        method: 'POST',
        credentials: 'include',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          amount: betAmount,
          risk: risk,
          rows: rows
        })
      });
      
      if (!res.ok) {
        const error = await res.json();
        throw new Error(error.detail || 'Failed to drop ball');
      }
      
      const data = await res.json();
      
      // Update balance immediately (deducted)
      setBalance(data.balance);
      
      // Play drop sound
      if (soundEnabled) playDropSound();
      
      // Create ball with slight random delay for visual variety when spamming
      const delay = Math.random() * 40;
      setTimeout(() => {
        createBall(data.path, data.bucket_index, data.balance, data.payout);
        setActiveBalls(prev => prev + 1);
      }, delay);
      
    } catch (err) {
      console.error('Drop error:', err);
    }
  };
  
  // ============================================
  // SPACEBAR HOLD TO DROP - Rapid fire mode
  // ============================================
  useEffect(() => {
    const handleKeyDown = (e) => {
      // Don't trigger if typing in an input
      if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
      
      if (e.code === 'Space') {
        e.preventDefault();
        
        // Only start interval on first press (not repeat)
        if (!e.repeat && !spaceHeldRef.current) {
          spaceHeldRef.current = true;
          
          // Drop first ball immediately
          dropBall();
          
          // Start interval for continuous drops
          dropIntervalRef.current = setInterval(() => {
            if (spaceHeldRef.current) {
              dropBall();
            }
          }, DROP_INTERVAL);
        }
      }
    };
    
    const handleKeyUp = (e) => {
      if (e.code === 'Space') {
        e.preventDefault();
        spaceHeldRef.current = false;
        
        // Clear the interval
        if (dropIntervalRef.current) {
          clearInterval(dropIntervalRef.current);
          dropIntervalRef.current = null;
        }
      }
    };
    
    // Cleanup when window loses focus (release spacebar)
    const handleBlur = () => {
      spaceHeldRef.current = false;
      if (dropIntervalRef.current) {
        clearInterval(dropIntervalRef.current);
        dropIntervalRef.current = null;
      }
    };
    
    window.addEventListener('keydown', handleKeyDown);
    window.addEventListener('keyup', handleKeyUp);
    window.addEventListener('blur', handleBlur);
    
    return () => {
      window.removeEventListener('keydown', handleKeyDown);
      window.removeEventListener('keyup', handleKeyUp);
      window.removeEventListener('blur', handleBlur);
      if (dropIntervalRef.current) {
        clearInterval(dropIntervalRef.current);
      }
    };
  }, [user, betAmount, balance, activeBalls, risk, rows, soundEnabled]);
  
  // ============================================
  // AUTO MODE - Automatic continuous drops
  // ============================================
  const autoIntervalRef = useRef(null);
  const autoRunningRef = useRef(false); // Ref to track running state in interval
  const [autoDropCount, setAutoDropCount] = useState(10); // Number of drops
  const [autoDropSpeed, setAutoDropSpeed] = useState(200); // ms between drops
  const [autoDropsRemaining, setAutoDropsRemaining] = useState(0);
  
  const startAutoMode = () => {
    if (!user || autoRunningRef.current) return;
    
    autoRunningRef.current = true;
    setAutoRunning(true);
    setAutoDropsRemaining(autoDropCount);
    
    let remaining = autoDropCount;
    
    // Drop first ball immediately
    dropBall();
    remaining--;
    setAutoDropsRemaining(remaining);
    
    // Continue dropping at interval
    autoIntervalRef.current = setInterval(() => {
      // Check ref instead of state (state has closure issues)
      if (remaining <= 0 || !autoRunningRef.current) {
        stopAutoMode();
        return;
      }
      
      dropBall();
      remaining--;
      setAutoDropsRemaining(remaining);
      
      if (remaining <= 0) {
        stopAutoMode();
      }
    }, autoDropSpeed);
  };
  
  const stopAutoMode = () => {
    autoRunningRef.current = false;
    setAutoRunning(false);
    setAutoDropsRemaining(0);
    if (autoIntervalRef.current) {
      clearInterval(autoIntervalRef.current);
      autoIntervalRef.current = null;
    }
  };
  
  // Cleanup auto mode on unmount
  useEffect(() => {
    return () => {
      if (autoIntervalRef.current) {
        clearInterval(autoIntervalRef.current);
      }
    };
  }, []);
  
  // ============================================
  // CREATE BALL - Plinko-style bouncy animation
  // ============================================
  const createBall = (path, targetBucket, serverBalance, serverPayout) => {
    if (!engineRef.current) return;
    
    const config = configRef.current;
    const numBuckets = rows + 1;
    const boardPadding = 40;
    const availableWidth = config.CANVAS_WIDTH - boardPadding * 2;
    const bucketWidth = availableWidth / numBuckets;
    
    // Peg layout calculations
    const pegAreaTop = config.START_Y;
    const pegAreaBottom = config.CANVAS_HEIGHT - config.BUCKET_HEIGHT - 20;
    const rowSpacing = (pegAreaBottom - pegAreaTop) / rows;
    
    // Build waypoints from server path
    const waypoints = [];
    let posIdx = 1;
    
    // Starting position
    waypoints.push({ 
      x: config.CANVAS_WIDTH / 2, 
      y: pegAreaTop - 25,
      type: 'start'
    });
    
    // Each peg bounce - realistic multi-bounce physics
    for (let row = 0; row < rows; row++) {
      const pegsInRow = row + 3;
      const rowWidth = (pegsInRow - 1) * bucketWidth;
      const rowStartX = (config.CANVAS_WIDTH - rowWidth) / 2;
      const pegX = rowStartX + posIdx * bucketWidth;
      const pegY = pegAreaTop + row * rowSpacing;
      const goRight = path && path[row] === 1;
      const dir = goRight ? 1 : -1;
      
      // 1. Hit the peg (ball touches peg)
      waypoints.push({ 
        x: pegX + dir * 2, 
        y: pegY, 
        pegX, pegY, 
        type: 'peg'
      });
      
      // 2. First bounce - big deflection upward
      waypoints.push({ 
        x: pegX + dir * bucketWidth * 0.22, 
        y: pegY + rowSpacing * 0.25, 
        type: 'bounce1',
        arcHeight: 12
      });
      
      // 3. Second bounce - medium
      waypoints.push({ 
        x: pegX + dir * bucketWidth * 0.32, 
        y: pegY + rowSpacing * 0.48, 
        type: 'bounce2',
        arcHeight: 7
      });
      
      // 4. Third small bounce - settling
      waypoints.push({ 
        x: pegX + dir * bucketWidth * 0.38, 
        y: pegY + rowSpacing * 0.68, 
        type: 'bounce3',
        arcHeight: 3
      });
      
      // 5. Final settle into position for next peg
      waypoints.push({ 
        x: pegX + dir * bucketWidth * 0.42, 
        y: pegY + rowSpacing * 0.90, 
        type: 'settle'
      });
      
      if (goRight) posIdx++;
    }
    
    // Final bucket position
    const bucketX = boardPadding + (targetBucket + 0.5) * bucketWidth;
    waypoints.push({ x: bucketX, y: config.CANVAS_HEIGHT - 12, type: 'bucket' });
    
    // Create ball (static - we animate manually)
    const ball = Bodies.circle(waypoints[0].x, waypoints[0].y, config.BALL_RADIUS, {
      isStatic: true,
      label: 'ball',
      collisionFilter: { group: -1 },
      render: {
        fillStyle: config.COLORS.ball,
        strokeStyle: config.COLORS.ballGlow,
        lineWidth: 2
      }
    });
    
    ball.betAmount = betAmount;
    ball.serverBalance = serverBalance;
    ball.serverPayout = serverPayout;
    ball.targetBucket = targetBucket;
    
    World.add(engineRef.current.world, ball);
    
    // Animation state
    let segmentIdx = 0;
    let segmentStart = performance.now();
    
    const animate = (now) => {
      if (!engineRef.current) return;
      
      // Done?
      if (segmentIdx >= waypoints.length - 1) {
        World.remove(engineRef.current.world, ball);
        onBallLand(ball, targetBucket);
        return;
      }
      
      const from = waypoints[segmentIdx];
      const to = waypoints[segmentIdx + 1];
      const elapsed = now - segmentStart;
      
      // Variable durations for different segment types
      let duration;
      if (to.type === 'peg') {
        duration = 32 + Math.random() * 6; // Quick fall to peg
      } else if (to.type === 'bounce1') {
        duration = 26 + Math.random() * 5; // Fast first bounce
      } else if (to.type === 'bounce2') {
        duration = 22 + Math.random() * 4; // Medium second bounce
      } else if (to.type === 'bounce3') {
        duration = 18 + Math.random() * 3; // Quick third bounce
      } else if (to.type === 'settle') {
        duration = 14 + Math.random() * 3; // Quick settle
      } else if (to.type === 'bucket') {
        duration = 55; // Slower fall to bucket
      } else {
        duration = 35;
      }
      
      let t = Math.min(elapsed / duration, 1);
      
      // Different easing for different phases
      let eased;
      if (to.type === 'peg') {
        // Accelerating into peg (ease-in quad)
        eased = t * t;
      } else if (to.type === 'bounce1' || to.type === 'bounce2' || to.type === 'bounce3') {
        // Quick bounce away (ease-out)
        eased = 1 - Math.pow(1 - t, 2);
      } else if (to.type === 'settle') {
        // Gentle settle (ease-out cubic)
        eased = 1 - Math.pow(1 - t, 3);
      } else {
        // Smooth ease-out for bucket
        eased = 1 - Math.pow(1 - t, 3);
      }
      
      // Interpolate position
      let x = from.x + (to.x - from.x) * eased;
      let y = from.y + (to.y - from.y) * eased;
      
      // Add bounce arc for bounce segments
      if (to.type === 'bounce1' || to.type === 'bounce2' || to.type === 'bounce3') {
        const arcHeight = to.arcHeight || 6;
        const arc = Math.sin(t * Math.PI) * arcHeight;
        y -= arc;
        // Slight horizontal wobble (less on smaller bounces)
        const wobble = to.type === 'bounce1' ? 1.5 : (to.type === 'bounce2' ? 0.8 : 0.4);
        x += Math.sin(t * Math.PI * 1.5) * wobble;
      }
      
      Body.setPosition(ball, { x, y });
      
      // Segment complete
      if (t >= 1) {
        // Flash peg and play sound on peg hit
        if (to.type === 'peg' && to.pegX !== undefined) {
          const bodies = engineRef.current.world.bodies;
          for (const b of bodies) {
            if (b.label === 'peg' && 
                Math.abs(b.position.x - to.pegX) < 10 && 
                Math.abs(b.position.y - to.pegY) < 10) {
              // Always reset to the base peg color (not current which might be green)
              b.render.fillStyle = config.COLORS.pegHit;
              // Clear any existing timeout on this peg
              if (b._flashTimeout) clearTimeout(b._flashTimeout);
              b._flashTimeout = setTimeout(() => { 
                b.render.fillStyle = config.COLORS.peg; 
                b._flashTimeout = null;
              }, 100);
              break;
            }
          }
          if (soundEnabled) playPegSound(segmentIdx / 4);
        }
        
        segmentIdx++;
        segmentStart = now;
      }
      
      requestAnimationFrame(animate);
    };
    
    requestAnimationFrame(animate);
  };
  
  // ============================================
  // SOUND EFFECTS - Premium casino-style addictive sounds
  // ============================================
  const audioCtxRef = useRef(null);
  const lastPegTimeRef = useRef(0);
  
  const getAudioContext = () => {
    if (!audioCtxRef.current || audioCtxRef.current.state === 'closed') {
      audioCtxRef.current = new (window.AudioContext || window.webkitAudioContext)();
    }
    if (audioCtxRef.current.state === 'suspended') {
      audioCtxRef.current.resume();
    }
    return audioCtxRef.current;
  };
  
  // Musical scale for ascending peg sounds (pentatonic for pleasing sound)
  const pegNotes = [523, 587, 659, 784, 880, 988, 1047, 1175, 1319, 1397, 1568, 1760, 1976, 2093, 2349, 2637];
  
  const playPegSound = (pegIndex = 0) => {
    try {
      const ctx = getAudioContext();
      const now = ctx.currentTime;
      
      // Throttle sounds slightly to prevent audio overload
      if (now - lastPegTimeRef.current < 0.015) return;
      lastPegTimeRef.current = now;
      
      // Musical ascending notes as ball goes down
      const noteIndex = Math.min(Math.floor(pegIndex), pegNotes.length - 1);
      const freq = pegNotes[noteIndex] + (Math.random() - 0.5) * 20;
      
      // Create a more complex, satisfying ping
      // Main tone
      const osc1 = ctx.createOscillator();
      const gain1 = ctx.createGain();
      osc1.connect(gain1);
      gain1.connect(ctx.destination);
      osc1.frequency.value = freq;
      osc1.type = 'sine';
      gain1.gain.setValueAtTime(0.08, now);
      gain1.gain.exponentialRampToValueAtTime(0.001, now + 0.08);
      osc1.start(now);
      osc1.stop(now + 0.1);
      
      // Octave harmonic (bright shimmer)
      const osc2 = ctx.createOscillator();
      const gain2 = ctx.createGain();
      osc2.connect(gain2);
      gain2.connect(ctx.destination);
      osc2.frequency.value = freq * 2;
      osc2.type = 'sine';
      gain2.gain.setValueAtTime(0.03, now);
      gain2.gain.exponentialRampToValueAtTime(0.001, now + 0.05);
      osc2.start(now);
      osc2.stop(now + 0.06);
      
      // Soft click for impact feel
      const clickOsc = ctx.createOscillator();
      const clickGain = ctx.createGain();
      clickOsc.connect(clickGain);
      clickGain.connect(ctx.destination);
      clickOsc.frequency.value = freq * 4;
      clickOsc.type = 'triangle';
      clickGain.gain.setValueAtTime(0.02, now);
      clickGain.gain.exponentialRampToValueAtTime(0.001, now + 0.02);
      clickOsc.start(now);
      clickOsc.stop(now + 0.025);
    } catch (e) {}
  };
  
  const playDropSound = () => {
    try {
      const ctx = getAudioContext();
      const now = ctx.currentTime;
      
      // Satisfying "whoosh" drop sound
      const osc = ctx.createOscillator();
      const gain = ctx.createGain();
      osc.connect(gain);
      gain.connect(ctx.destination);
      osc.frequency.setValueAtTime(600, now);
      osc.frequency.exponentialRampToValueAtTime(200, now + 0.1);
      osc.type = 'sine';
      gain.gain.setValueAtTime(0.06, now);
      gain.gain.exponentialRampToValueAtTime(0.001, now + 0.12);
      osc.start(now);
      osc.stop(now + 0.15);
    } catch (e) {}
  };
  
  const playWinSound = () => {
    try {
      const ctx = getAudioContext();
      const now = ctx.currentTime;
      
      // Triumphant ascending arpeggio (slot machine jackpot style)
      const notes = [523, 659, 784, 1047, 1319, 1568]; // C major scale up
      notes.forEach((freq, i) => {
        const osc = ctx.createOscillator();
        const gain = ctx.createGain();
        osc.connect(gain);
        gain.connect(ctx.destination);
        osc.frequency.value = freq;
        osc.type = 'sine';
        gain.gain.setValueAtTime(0.12, now + i * 0.08);
        gain.gain.exponentialRampToValueAtTime(0.001, now + i * 0.08 + 0.3);
        osc.start(now + i * 0.08);
        osc.stop(now + i * 0.08 + 0.35);
        
        // Add shimmer
        const osc2 = ctx.createOscillator();
        const gain2 = ctx.createGain();
        osc2.connect(gain2);
        gain2.connect(ctx.destination);
        osc2.frequency.value = freq * 2.01; // Slight detune for shimmer
        osc2.type = 'sine';
        gain2.gain.setValueAtTime(0.04, now + i * 0.08);
        gain2.gain.exponentialRampToValueAtTime(0.001, now + i * 0.08 + 0.25);
        osc2.start(now + i * 0.08);
        osc2.stop(now + i * 0.08 + 0.3);
      });
      
      // Coin drop sounds
      for (let i = 0; i < 5; i++) {
        const osc = ctx.createOscillator();
        const gain = ctx.createGain();
        osc.connect(gain);
        gain.connect(ctx.destination);
        osc.frequency.value = 2000 + Math.random() * 2000;
        osc.type = 'sine';
        const delay = 0.3 + i * 0.06 + Math.random() * 0.03;
        gain.gain.setValueAtTime(0.05, now + delay);
        gain.gain.exponentialRampToValueAtTime(0.001, now + delay + 0.05);
        osc.start(now + delay);
        osc.stop(now + delay + 0.06);
      }
    } catch (e) {}
  };
  
  const playLoseSound = () => {
    try {
      const ctx = getAudioContext();
      const now = ctx.currentTime;
      
      // Soft descending tone (not harsh, keeps player engaged)
      const osc = ctx.createOscillator();
      const gain = ctx.createGain();
      osc.connect(gain);
      gain.connect(ctx.destination);
      osc.frequency.setValueAtTime(400, now);
      osc.frequency.exponentialRampToValueAtTime(200, now + 0.15);
      osc.type = 'sine';
      gain.gain.setValueAtTime(0.04, now);
      gain.gain.exponentialRampToValueAtTime(0.001, now + 0.2);
      osc.start(now);
      osc.stop(now + 0.25);
      
      // Soft thud
      const osc2 = ctx.createOscillator();
      const gain2 = ctx.createGain();
      osc2.connect(gain2);
      gain2.connect(ctx.destination);
      osc2.frequency.value = 80;
      osc2.type = 'sine';
      gain2.gain.setValueAtTime(0.06, now);
      gain2.gain.exponentialRampToValueAtTime(0.001, now + 0.1);
      osc2.start(now);
      osc2.stop(now + 0.12);
    } catch (e) {}
  };
  
  const playBigWinSound = () => {
    try {
      const ctx = getAudioContext();
      const now = ctx.currentTime;
      
      // Dramatic fanfare for big multipliers
      const fanfare = [523, 659, 784, 1047, 784, 1047, 1319];
      fanfare.forEach((freq, i) => {
        const osc = ctx.createOscillator();
        const gain = ctx.createGain();
        osc.connect(gain);
        gain.connect(ctx.destination);
        osc.frequency.value = freq;
        osc.type = 'sawtooth';
        gain.gain.setValueAtTime(0.08, now + i * 0.1);
        gain.gain.exponentialRampToValueAtTime(0.001, now + i * 0.1 + 0.4);
        osc.start(now + i * 0.1);
        osc.stop(now + i * 0.1 + 0.45);
      });
      
      // Sparkle overlay
      for (let i = 0; i < 12; i++) {
        const osc = ctx.createOscillator();
        const gain = ctx.createGain();
        osc.connect(gain);
        gain.connect(ctx.destination);
        osc.frequency.value = 1500 + Math.random() * 3000;
        osc.type = 'sine';
        const delay = Math.random() * 0.8;
        gain.gain.setValueAtTime(0.03, now + delay);
        gain.gain.exponentialRampToValueAtTime(0.001, now + delay + 0.08);
        osc.start(now + delay);
        osc.stop(now + delay + 0.1);
      }
    } catch (e) {}
  };
  
  // ============================================
  // BET INPUT HANDLER
  // ============================================
  const handleBetChange = (value) => {
    setBetDisplay(value);
    const cents = parseCoinsInput(value);
    setBetAmount(cents);
  };
  
  const handleBetBlur = () => {
    setBetDisplay(formatCoins(betAmount));
  };
  
  // ============================================
  // GET BUCKET TIER FOR STYLING
  // ============================================
  const getBucketTier = (index) => {
    const mult = multipliers[index] || 1;
    if (mult >= 100) return 'tier-1';
    if (mult >= 50) return 'tier-1';
    if (mult >= 20) return 'tier-2';
    if (mult >= 10) return 'tier-2';
    if (mult >= 5) return 'tier-3';
    if (mult >= 2) return 'tier-4';
    if (mult >= 1) return 'tier-5';
    if (mult >= 0.5) return 'tier-6';
    return 'tier-7';
  };
  
  // ============================================
  // RENDER
  // ============================================
  const config = configRef.current;
  
  // Get global components
  const NavbarComponent = window.CoinRushNavbar;
  const ChatComponent = window.CoinRushChatApp;
  const AuthModalComponent = window.AuthModal;
  
  // Handle auth success
  const handleAuthSuccess = (userData) => {
    setUser(userData);
    setBalance(userData.balance || 0);
    setShowAuthModal(false);
  };
  
  return (
    <div className="plinko-app">
      {/* Navbar */}
      {NavbarComponent && (
        <NavbarComponent 
          user={user}
          activePage="plinko"
          isConnected={wsConnected}
        />
      )}
      
      {/* Auth Modal */}
      {AuthModalComponent && (
        <AuthModalComponent 
          isOpen={showAuthModal}
          onClose={() => setShowAuthModal(false)}
          onSuccess={handleAuthSuccess}
        />
      )}
      
      <div className="plinko-container">
        {/* Left Panel - Controls */}
        <div className="plinko-controls">
          <div className="pk-card">
            {/* Mode Tabs */}
            <div className="pk-mode-tabs">
              <button 
                className={`pk-mode-tab ${!autoMode ? 'active' : ''}`}
                onClick={() => setAutoMode(false)}
              >
                Manual
              </button>
              <button 
                className={`pk-mode-tab ${autoMode ? 'active' : ''}`}
                onClick={() => setAutoMode(true)}
              >
                Auto
              </button>
            </div>
            
            {/* Bet Amount */}
            <div className="pk-input-group">
              <label className="pk-input-label">
                <span>Bet Amount</span>
                <span style={{ color: 'var(--pk-green)' }}>{formatCoins(balance)}</span>
              </label>
              <div className="pk-input-wrapper">
                <span className="pk-input-icon"><Icons.coin /></span>
                <input
                  type="text"
                  className="pk-input"
                  value={betDisplay}
                  onChange={(e) => handleBetChange(e.target.value)}
                  onBlur={handleBetBlur}
                  onFocus={(e) => e.target.select()}
                />
                <button 
                  className="pk-input-btn"
                  onClick={() => {
                    const newBet = Math.max(100, Math.floor(betAmount / 2));
                    setBetAmount(newBet);
                    setBetDisplay(formatCoins(newBet));
                  }}
                >
                  ½
                </button>
                <button 
                  className="pk-input-btn"
                  onClick={() => {
                    const newBet = Math.min(betAmount * 2, balance);
                    setBetAmount(newBet);
                    setBetDisplay(formatCoins(newBet));
                  }}
                >
                  2×
                </button>
              </div>
            </div>
            
            {/* Risk Level */}
            <div className="pk-input-group">
              <label className="pk-input-label">
                <span>Risk</span>
              </label>
              <div className="pk-risk-selector">
                {['low', 'medium', 'high'].map(r => (
                  <button
                    key={r}
                    className={`pk-risk-btn ${r} ${risk === r ? 'active' : ''}`}
                    onClick={() => setRisk(r)}
                  >
                    {r}
                  </button>
                ))}
              </div>
            </div>
            
            {/* Rows */}
            <div className="pk-input-group">
              <label className="pk-input-label">
                <span>Rows</span>
                <span>{rows}</span>
              </label>
              <input
                type="range"
                className="pk-rows-slider"
                min="8"
                max="16"
                value={rows}
                onChange={(e) => setRows(parseInt(e.target.value))}
              />
              <div className="pk-rows-markers">
                {[8, 10, 12, 14, 16].map(r => (
                  <span 
                    key={r} 
                    className={rows === r ? 'active' : ''}
                    onClick={() => setRows(r)}
                  >
                    {r}
                  </span>
                ))}
              </div>
            </div>
            
            {/* Auto Mode Controls */}
            {autoMode && (
              <div className="pk-auto-controls">
                {/* Number of Drops */}
                <div className="pk-input-group">
                  <label className="pk-input-label">
                    <span>Number of Drops</span>
                    <span>{autoDropCount}</span>
                  </label>
                  <div className="pk-auto-presets">
                    {[10, 25, 50, 100].map(n => (
                      <button
                        key={n}
                        className={`pk-preset-btn ${autoDropCount === n ? 'active' : ''}`}
                        onClick={() => setAutoDropCount(n)}
                        disabled={autoRunning}
                      >
                        {n}
                      </button>
                    ))}
                  </div>
                </div>
                
                {/* Drop Speed */}
                <div className="pk-input-group">
                  <label className="pk-input-label">
                    <span>Speed</span>
                    <span>{autoDropSpeed}ms</span>
                  </label>
                  <div className="pk-auto-presets">
                    {[{label: 'Slow', val: 400}, {label: 'Normal', val: 200}, {label: 'Fast', val: 100}, {label: 'Turbo', val: 50}].map(s => (
                      <button
                        key={s.val}
                        className={`pk-preset-btn ${autoDropSpeed === s.val ? 'active' : ''}`}
                        onClick={() => setAutoDropSpeed(s.val)}
                        disabled={autoRunning}
                      >
                        {s.label}
                      </button>
                    ))}
                  </div>
                </div>
                
                {/* Auto Status */}
                {autoRunning && (
                  <div className="pk-auto-status">
                    <span>Drops remaining: {autoDropsRemaining}</span>
                  </div>
                )}
              </div>
            )}
            
            {/* Bet Button */}
            <button
              className={`pk-bet-btn ${isDropping || autoRunning ? 'dropping' : ''}`}
              onClick={autoMode ? (autoRunning ? stopAutoMode : startAutoMode) : dropBall}
              disabled={!user && false}
            >
              {autoMode ? (
                autoRunning ? (
                  <span>Stop Auto ({autoDropsRemaining})</span>
                ) : (
                  <span>Start Auto ({autoDropCount} drops)</span>
                )
              ) : !user ? (
                <span>Login to Play</span>
              ) : (
                <span>Drop Ball</span>
              )}
            </button>
            
            {/* Connection Status */}
            <div className="pk-connection-status">
              <span className={`pk-status-dot ${wsConnected ? 'connected' : ''}`}></span>
              <span>{wsConnected ? 'Connected' : 'Connecting...'}</span>
            </div>
          </div>
          
          {/* History */}
          <div className="pk-card pk-history">
            <div className="pk-card-header">
              <span className="pk-card-title">Recent Drops</span>
            </div>
            <div className="pk-history-list">
              {history.map((h, i) => (
                <div key={i} className={`pk-history-item ${h.isWin ? 'win' : 'loss'}`}>
                  {h.multiplier.toFixed(2)}×
                </div>
              ))}
              {history.length === 0 && (
                <span className="pk-no-history">No drops yet</span>
              )}
            </div>
          </div>
        </div>
        
        {/* Main Game Area */}
        <div className="plinko-game-area">
          <div className="pk-board-container">
            <div className="pk-board-header">
              <span className="pk-board-title">
                <span className="pk-title-icon"><Icons.slotMachine /></span>
                Plinko
              </span>
              <div className="pk-fairness-badge">
                <span><Icons.check /></span>
                <span>Provably Fair</span>
              </div>
            </div>
            
            {/* Canvas */}
            <div className="pk-canvas-container">
              <canvas ref={canvasRef} id="plinko-canvas" />
              
              {/* Sound Toggle */}
              <button 
                className="pk-sound-toggle"
                onClick={() => setSoundEnabled(!soundEnabled)}
                title={soundEnabled ? 'Mute' : 'Unmute'}
              >
                {soundEnabled ? <Icons.volumeOn /> : <Icons.volumeOff />}
              </button>
            </div>
            
            {/* Multiplier Buckets - aligned with canvas buckets */}
            <div className="pk-buckets" style={{ padding: '0 40px' }}>
              {multipliers.map((mult, i) => (
                <div 
                  key={i} 
                  className={`pk-bucket ${getBucketTier(i)} ${lastResult?.bucketIndex === i ? 'highlight winning' : ''}`}
                >
                  {mult >= 100 ? mult.toFixed(0) : mult.toFixed(1)}x
                </div>
              ))}
            </div>
          </div>
        </div>
        
        {/* Right Panel - Chat */}
        <div className="plinko-chat">
          {ChatComponent && <ChatComponent currentUser={user} theme="green" />}
        </div>
      </div>
      
      {/* Result Popup */}
      {showResult && lastResult && (
        <div className={`pk-result-popup show ${lastResult.isWin ? 'win' : 'loss'}`}>
          <div className="pk-result-multiplier">{lastResult.multiplier.toFixed(2)}×</div>
          <div className="pk-result-payout">
            {lastResult.isWin ? '+' : ''}{formatCoins(lastResult.profit)}
          </div>
        </div>
      )}
      
      {/* Wallet Modals */}
      {window.WalletModals && <window.WalletModals />}
    </div>
  );
}

// ============================================
// MOUNT APP
// ============================================
const plinkoRoot = document.getElementById('plinko-root');
if (plinkoRoot) {
  ReactDOM.createRoot(plinkoRoot).render(<PlinkoGame />);
}
