require('dotenv').config();
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
const path = require('path');

app.use(express.static(path.join(__dirname, '../public')));

// Room State
const rooms = {};
const RECONNECT_GRACE_PERIOD = 10000; // 10 seconds
const disconnectedPlayers = new Map(); // Track recently disconnected players
const roomTimeouts = new Map(); // Track room cleanup timeouts

// Ludo board positions: -1 = home, 0-51 = main track, 52-57 = home stretch, 100 = finished
function createInitialGameState() {
    return {
        board: {
            red: [-1, -1, -1, -1],      // 4 pieces in home
            blue: [-1, -1, -1, -1],
            green: [-1, -1, -1, -1],
            yellow: [-1, -1, -1, -1]
        },
        currentTurn: 'red',
        diceValue: null,
        extraTurn: false,
        gameActive: false,
        winner: null,
        rankings: [],  // Array to track finish order: [{ color: 'red', rank: 1, timestamp: ... }, ...]
        playerCount: 0,
        lastMove: null
    };
}

// Export a function that accepts the IO instance and namespace
module.exports = function(ioInstance, appInstance, roomsDB, appEmitter) {
    // If roomsDB is not passed (standalone mode), try to require it
    if (!roomsDB) {
        try {
            roomsDB = require('../../../admin/server/rooms-db');
        } catch (e) {
            console.warn('Ludo: Could not load roomsDB for standalone mode');
        }
    }

    // Function to load rooms from DB
    const loadRooms = () => {
        if (!roomsDB) return;
        
        try {
            // Fetch ALL rooms to distinguish between 'inactive' and 'deleted'
            const dbRooms = roomsDB.getRoomsByGame('ludo');
            const dbRoomIds = new Set();

            // 1. Update/Add rooms
            dbRooms.forEach(room => {
                const roomId = `room_${room.id}`;
                dbRoomIds.add(roomId);
                
                if (room.status === 'active') {
                    // ACTIVE ROOMS: Load or Update
                    if (rooms[roomId]) {
                        // Update existing room properties
                        rooms[roomId].name = room.name;
                        rooms[roomId].password = room.password || null;
                        rooms[roomId].type = room.type;
                        rooms[roomId].isProtected = !!room.password;
                        rooms[roomId].isArchived = false; // Ensure not archived
                    } else {
                        // Create new room
                        rooms[roomId] = {
                            id: roomId,
                            name: room.name,
                            password: room.password || null,
                            type: room.type,
                            isProtected: !!room.password,
                            players: { red: null, blue: null, green: null, yellow: null },
                            gameState: createInitialGameState(),
                            isActive: false,
                            chatHistory: []
                        };
                    }
                } else {
                    // INACTIVE ROOMS: "Just make inactive" (Remove immediately)
                    // If the room exists in memory but is now inactive in DB, remove it.
                    if (rooms[roomId]) {
                        // Notify players before deleting
                        if (ioInstance) {
                            ioInstance.to(roomId).emit('chat_message', {
                                id: Date.now() + '_sys',
                                sender: 'System',
                                role: 'system',
                                text: '⚠️ This room has been deactivated by the admin.',
                                timestamp: Date.now(),
                                seenBy: []
                            });
                        }
                        delete rooms[roomId];
                    }
                }
            });

            // 2. Handle Deleted Rooms (Rooms in memory but NOT in DB)
            // These should be Archived (Graceful Shutdown)
            Object.keys(rooms).forEach(roomId => {
                if (!dbRoomIds.has(roomId)) {
                    // Room DELETED from DB
                    const room = rooms[roomId];
                    const playerCount = Object.values(room.players).filter(p => p !== null).length;
                    
                    if (playerCount === 0) {
                        // Empty room - delete immediately
                        delete rooms[roomId];
                    } else {
                        // Active room - mark as archived (graceful shutdown)
                        if (!room.isArchived) {
                            room.isArchived = true;
                            // Notify players
                            if (ioInstance) {
                                ioInstance.to(roomId).emit('chat_message', {
                                    id: Date.now() + '_sys',
                                    sender: 'System',
                                    role: 'system',
                                    text: '⚠️ This room has been deleted by the admin. You may finish your current game, but no new players can join.',
                                    timestamp: Date.now(),
                                    seenBy: []
                                });
                            }
                        }
                    }
                }
            });

            console.log(`Ludo: Reloaded rooms. Total: ${Object.keys(rooms).length}`);
            
            // Broadcast new room list to all connected clients
            if (ioInstance) {
                ioInstance.emit('room_list', getRoomList());
            }

        } catch (error) {
            console.error('Ludo: Error loading rooms from database:', error);
        }
    };

    // Initial Load
    if (roomsDB) {
        loadRooms();
        
        // Listen for updates
        if (appEmitter) {
            appEmitter.on('room_update', ({ gameType }) => {
                if (gameType === 'ludo' || !gameType) {
                    console.log('Ludo: Received room update event, reloading...');
                    loadRooms();
                }
            });
        }
    } else {
        // Fallback to .env configuration
        let roomCount = 0;
        for (let i = 1; i <= 100; i++) {
            if (process.env[`LUDO_ROOM_${i}_NAME`]) {
                roomCount = i;
            } else if (i > roomCount + 5) {
                break;
            }
        }

        // Initialize rooms found in .env
        for (let i = 1; i <= roomCount; i++) {
            const envName = process.env[`LUDO_ROOM_${i}_NAME`];
            const envPass = process.env[`LUDO_ROOM_${i}_PASS`];
            const envType = process.env[`LUDO_ROOM_${i}_TYPE`] || 'private';
            
            const roomType = (envType === 'public' || envType === 'private') ? envType : 'private';
            
            if (envName) {
                rooms[`room_${i}`] = {
                    id: `room_${i}`,
                    name: envName,
                    password: envPass || null,
                    type: roomType,
                    isProtected: !!envPass,
                    players: { red: null, blue: null, green: null, yellow: null },
                    gameState: createInitialGameState(),
                    isActive: false,
                    chatHistory: []
                };
            }
        }
        console.log(`Ludo: Initialized ${Object.keys(rooms).length} rooms from .env`);
    }

    const router = express.Router();
    
    if (appInstance) {
        router.use(express.static(path.join(__dirname, '../public')));
        appInstance.use('/games/ludo', router);
    }

    const ioToUse = ioInstance || io;
    
    const onConnection = (socket) => {
        console.log('User connected to Ludo:', socket.id);
    
        socket.emit('room_list', getRoomList());
    
        socket.on('get_rooms', () => {
            socket.emit('room_list', getRoomList());
        });
    
        socket.on('get_players', ({ roomId }) => {
            const room = rooms[roomId];
            if (room) {
                socket.emit('player_update', getPublicPlayers(room));
            }
        });
    
        socket.on('join_room', ({ roomId, password, color, playerName }) => {
            const room = rooms[roomId];
            if (!room) return socket.emit('error', 'Room not found');
            
            // Prevent joining archived rooms
            if (room.isArchived) {
                return socket.emit('error', 'This room has been closed by the admin.');
            }
    
            // Check reconnection
            const disconnectKey = `${roomId}:${color}:${playerName}`;
            const disconnectedInfo = disconnectedPlayers.get(disconnectKey);
            
            if (disconnectedInfo) {
                console.log(`[JOIN] Reconnecting...`);
                disconnectedPlayers.delete(disconnectKey);
                
                // Clear any pending player-specific timeout
                if (disconnectedInfo.timeout) {
                    console.log(`[JOIN] Clearing player timeout`);
                    clearTimeout(disconnectedInfo.timeout);
                }
                
                // Clear the room-level cleanup timeout since a player is reconnecting
                if (roomTimeouts.has(roomId)) {
                    console.log(`Clearing room cleanup timeout for ${roomId} - player reconnecting`);
                    clearTimeout(roomTimeouts.get(roomId));
                    roomTimeouts.delete(roomId);
                }
                
                // Verify password matches what they had before
                if (disconnectedInfo.password !== password) {
                    console.log(`PASSWORD MISMATCH! Saved: "${disconnectedInfo.password}", Provided: "${password}"`);
                    return socket.emit('error', 'Incorrect password');
                }
                console.log('Password verified, allowing reconnection');
            } else {
                // Password validation
                if (room.isProtected) {
                    if (room.password !== password) {
                        return socket.emit('error', 'Incorrect password');
                    }
                    room.isActive = true;
                } else {
                    if (room.isActive) {
                        if (room.password && room.password !== password) {
                            return socket.emit('error', 'Incorrect password');
                        }
                    } else {
                        // Check if room is still empty
                        if (Object.values(room.players).every(p => p === null)) {
                            
                            // If room is archived and empty, delete it permanently
                            if (room.isArchived) {
                                delete rooms[roomId];
                                return;
                            }

                            // Only reset password if it wasn't pre-set
                            room.password = password;
                            room.isActive = true;
                        } else if (room.password !== password) {
                            return socket.emit('error', 'Incorrect password');
                        }
                    }
                }
    
                // Check color availability
                if (room.players[color]) {
                    // CRITICAL FIX: If player exists but it's the SAME player (name matches) 
                    // and just hasn't been fully disconnected yet (race condition), allow rejoin.
                    if (room.players[color].name === playerName) {
                        console.log(`[JOIN] Player ${playerName} (${color}) found in room but status is ${room.players[color].status}. Treating as immediate reconnect.`);
                        
                        // Force disconnect the old socket if it's different
                        if (room.players[color].id !== socket.id) {
                            console.log(`[JOIN] Overwriting old socket ${room.players[color].id} with new ${socket.id}`);
                        }
                        // Proceed to join (overwrite)
                    } else {
                        return socket.emit('error', `Color ${color} is already taken`);
                    }
                }
    
                // Check name uniqueness (if not the same player we just handled above)
                const existingPlayer = Object.values(room.players).find(p => p && p.name === playerName && p !== room.players[color]);
                if (existingPlayer) {
                    return socket.emit('error', `Name "${playerName}" is already taken in this room`);
                }
            }
    
            // Join Room
            socket.join(roomId);
            room.players[color] = { 
                id: socket.id, 
                name: playerName, 
                status: 'online',
                joinedAt: Date.now()
            };
            
            room.gameState.playerCount = Object.values(room.players).filter(p => p !== null).length;
            
            socket.emit('joined_room', { 
                roomId, 
                color, 
                gameState: room.gameState,
                players: getPublicPlayers(room),
                chatHistory: room.chatHistory || []
            });
    
            ioToUse.to(roomId).emit('player_update', getPublicPlayers(room));
            ioToUse.emit('room_list', getRoomList());
            
            // Start game if 2+ players
            if (room.gameState.playerCount >= 2 && !room.gameState.gameActive) {
                // Generate unique numeric match ID (timestamp + random suffix)
                room.currentMatchId = Date.now() * 1000 + Math.floor(Math.random() * 1000);
                
                room.gameState.gameActive = true;
                ioToUse.to(roomId).emit('game_start', {
                    gameState: room.gameState,
                    matchId: room.currentMatchId
                });
            }
        });
    
        socket.on('player_status', ({ roomId, status }) => {
            const room = rooms[roomId];
            if (!room) return;
    
            const color = getPlayerColor(room, socket.id);
            if (color && room.players[color]) {
                room.players[color].status = status;
                ioToUse.to(roomId).emit('player_status_update', {
                    players: getPublicPlayers(room)
                });
            }
        });
    
        socket.on('roll_dice', ({ roomId }) => {
            const room = rooms[roomId];
            if (!room || !room.gameState.gameActive) return;
            
            const playerColor = getPlayerColor(room, socket.id);
            if (!playerColor || room.gameState.currentTurn !== playerColor) return;
            
            if (room.gameState.diceValue !== null) return; // Dice already rolled, waiting for move
            
            const diceValue = Math.floor(Math.random() * 6) + 1;
            room.gameState.diceValue = diceValue;
            room.gameState.extraTurn = (diceValue === 6);
            
            ioToUse.to(roomId).emit('dice_rolled', { 
                diceValue, 
                player: playerColor,
                extraTurn: room.gameState.extraTurn
            });
            
            // Check if player has any valid moves
            if (!hasValidMoves(room.gameState, playerColor)) {
                // No valid moves, skip turn
                setTimeout(() => {
                    nextTurn(room, ioToUse, roomId);
                }, 2000);
            }
        });
    
        socket.on('move_piece', ({ roomId, pieceIndex, steps }) => {
            const room = rooms[roomId];
            if (!room) return;
            
            const playerColor = getPlayerColor(room, socket.id);
            if (!playerColor || room.gameState.currentTurn !== playerColor) return;
            
            if (room.gameState.diceValue === null) return;
            
            const isValid = validateMove(room.gameState, playerColor, pieceIndex, room.gameState.diceValue);
            if (!isValid) return socket.emit('error', 'Invalid move');
            
            applyMove(room.gameState, playerColor, pieceIndex, room.gameState.diceValue);
            
            ioToUse.to(roomId).emit('update_game', { gameState: room.gameState });
            
            // Check if player just finished
            if (checkWinCondition(room.gameState, playerColor)) {
                // Player finished! Record their rank
                const alreadyRanked = room.gameState.rankings.find(r => r.color === playerColor);
                
                if (!alreadyRanked) {
                    const rank = room.gameState.rankings.length + 1;
                    room.gameState.rankings.push({
                        color: playerColor,
                        rank: rank,
                        timestamp: Date.now()
                    });
                    
                    // Set first finisher as winner
                    if (rank === 1) {
                        room.gameState.winner = playerColor;
                    }
                    
                    // Notify all players about this player's finish
                    ioToUse.to(roomId).emit('player_finished', {
                        color: playerColor,
                        rank: rank,
                        rankings: room.gameState.rankings
                    });
                    
                    // Check if game should end
                    // Count only players who actually joined (not empty slots)
                    const colors = ['red', 'blue', 'green', 'yellow'];
                    const activePlayers = colors.filter(c => room.players[c] !== null).length;
                    const finishedPlayers = room.gameState.rankings.length;
                    
                    // Game ends when N-1 players finish (leaving 1 player remaining)
                    // Examples: 2 players -> ends when 1 finishes, 3 players -> ends when 2 finish
                    if (finishedPlayers >= activePlayers - 1 && activePlayers > 1) {
                        // Game over - assign rank to remaining player(s) if any
                        const finishedColors = room.gameState.rankings.map(r => r.color);
                        const remainingPlayers = colors.filter(c => room.players[c] !== null && !finishedColors.includes(c));
                        
                        // Assign last place to remaining player(s)
                        remainingPlayers.forEach(color => {
                            const lastRank = room.gameState.rankings.length + 1;
                            room.gameState.rankings.push({
                                color: color,
                                rank: lastRank,
                                timestamp: Date.now()
                            });
                        });
                        
                        room.gameState.gameActive = false;
                        ioToUse.to(roomId).emit('game_over', { 
                            rankings: room.gameState.rankings,
                            winner: room.gameState.winner
                        });
                    } else {
                        // Continue game - next turn
                        nextTurn(room, ioToUse, roomId);
                    }
                } else {
                    // Player already finished, just continue
                    nextTurn(room, ioToUse, roomId);
                }
            } else {
                // Player hasn't finished yet, next turn
                nextTurn(room, ioToUse, roomId);
            }
        });
    
        socket.on('restart_game', ({ roomId }) => {
            const room = rooms[roomId];
            if (!room) return;
            
            room.gameState = createInitialGameState();
            room.gameState.playerCount = Object.values(room.players).filter(p => p !== null).length;
            room.gameState.gameActive = (room.gameState.playerCount >= 2);
            room.chatHistory = [];
            
            // Generate new unique numeric match ID for restarted game
            room.currentMatchId = Date.now() * 1000 + Math.floor(Math.random() * 1000);
            
            ioToUse.to(roomId).emit('game_start', {
                gameState: room.gameState,
                matchId: room.currentMatchId
            });
            ioToUse.to(roomId).emit('chat_cleared');
        });
    
        socket.on('leave_room', ({ roomId }) => {
            handleLeave(socket, roomId, ioToUse);
        });
    
        socket.on('chat_message', ({ roomId, message }) => {
            const room = rooms[roomId];
            if (!room) return;
            
            const color = getPlayerColor(room, socket.id);
            if (!color) return;
            
            const player = room.players[color];
            
            const chatMessage = {
                id: Date.now() + '_' + color,
                sender: player.name,
                role: color,
                color: color,
                text: message,
                timestamp: Date.now(),
                seenBy: [color]
            };
            
            if (!room.chatHistory) room.chatHistory = [];
            room.chatHistory.push(chatMessage);
            if (room.chatHistory.length > 50) {
                room.chatHistory.shift();
            }
            
            ioToUse.to(roomId).emit('chat_message', chatMessage);
        });
    
        socket.on('mark_messages_seen', ({ roomId }) => {
            const room = rooms[roomId];
            if (!room) return;
            
            const color = getPlayerColor(room, socket.id);
            if (!color) return;
            
            if (room.chatHistory) {
                const seenMessageIds = [];
                room.chatHistory.forEach(msg => {
                    if (!msg.seenBy.includes(color)) {
                        msg.seenBy.push(color);
                        seenMessageIds.push(msg.id);
                    }
                });
                
                if (seenMessageIds.length > 0) {
                    socket.to(roomId).emit('messages_seen', {
                        seenBy: color,
                        messageIds: seenMessageIds
                    });
                }
            }
        });
    
        socket.on('disconnect', () => {
            for (const roomId in rooms) {
                const room = rooms[roomId];
                const colors = ['red', 'blue', 'green', 'yellow'];
                for (const color of colors) {
                    if (room.players[color]?.id === socket.id) {
                        handleLeave(socket, roomId, ioToUse);
                    }
                }
            }
        });
    };

    ioToUse.on('connection', onConnection);
    
    return router;
};

// Standalone execution
if (require.main === module) {
    app.use(express.static(path.join(__dirname, '../public')));
    const PORT = process.env.PORT || 3003;
    server.listen(PORT, () => {
      console.log(`Ludo server listening on *:${PORT}`);
    });
    
    module.exports(io);
}

function handleLeave(socket, roomId, ioInstance) {
    console.log(`[LEAVE] handleLeave called for socket ${socket.id} in room ${roomId}`);
    const room = rooms[roomId];
    if (!room) {
        console.log(`[LEAVE] Room ${roomId} not found`);
        return;
    }

    const color = getPlayerColor(room, socket.id);
    console.log(`[LEAVE] Player color: ${color}`);
    
    if (color) {
        const playerInfo = room.players[color];
        
        // Store disconnected player info for reconnection grace period
        const disconnectKey = `${roomId}:${color}:${playerInfo.name}`;
        console.log(`[LEAVE] Player ${playerInfo.name} (${color}) disconnecting. Key: ${disconnectKey}`);
        
        // Create timeout to remove player from room if they don't return
        const playerTimeoutId = setTimeout(() => {
            console.log(`[TIMEOUT] Player grace period expired for ${playerInfo.name} (${color})`);
            
            // Check if still disconnected (and room still exists)
            if (rooms[roomId] && rooms[roomId].players[color] && rooms[roomId].players[color].status === 'disconnected') {
                 console.log(`[TIMEOUT] Removing player ${color} from room`);
                 rooms[roomId].players[color] = null; // Remove from room
                 disconnectedPlayers.delete(disconnectKey); // Remove from reconnect map
                 rooms[roomId].gameState.playerCount = Object.values(rooms[roomId].players).filter(p => p !== null).length;
                 
                 // Notify others
                 ioInstance.to(roomId).emit('player_update', getPublicPlayers(rooms[roomId]));
                 ioInstance.emit('room_list', getRoomList());
            }
        }, RECONNECT_GRACE_PERIOD);

        disconnectedPlayers.set(disconnectKey, {
            roomId,
            color,
            name: playerInfo.name,
            password: room.password,
            gameState: room.gameState,
            timeout: playerTimeoutId // Store timeout to clear on reconnect
        });
        console.log(`[LEAVE] Set disconnectedPlayers entry for ${disconnectKey}`);
        
        room.players[color].status = 'disconnected'; // Mark as disconnected
        socket.leave(roomId);
        
        // Notify other players that this player left
        ioInstance.to(roomId).emit('player_left', { color });
        
        // Check if all players are now disconnected
        const allPlayersGone = Object.values(room.players).every(p => !p || p.status === 'disconnected');
        // Notify others that player disconnected
        ioInstance.to(roomId).emit('player_update', getPublicPlayers(room));
        ioInstance.emit('room_list', getRoomList());
        
        if (allPlayersGone) {
            // All players disconnected - start room cleanup timeout
            // Clear any existing timeout first
            if (roomTimeouts.has(roomId)) {
                clearTimeout(roomTimeouts.get(roomId));
            }
            
            console.log(`All players disconnected from ${roomId}. Starting ${RECONNECT_GRACE_PERIOD}ms grace period...`);
            
            const roomTimeoutId = setTimeout(() => {
                console.log(`Grace period expired for ${roomId}. Checking if room is still empty...`);
                
                // Double-check room is still empty (in case someone reconnected)
                const stillEmpty = room.players && Object.values(room.players).every(p => !p || p.status === 'disconnected');
                
                if (stillEmpty) {
                    console.log(`Room ${roomId} still empty. Resetting...`);
                    
                    // Clean up all disconnected players for this room
                    for (const key of disconnectedPlayers.keys()) {
                        if (key.startsWith(`${roomId}:`)) {
                            disconnectedPlayers.delete(key);
                        }
                    }
                    
                    // Explicitly remove players now that grace period is over
                    room.players = { red: null, blue: null, green: null, yellow: null };
                    
                    // If room is archived and empty, delete it permanently
                    if (room.isArchived) {
                        delete rooms[roomId];
                        ioInstance.emit('room_list', getRoomList());
                        roomTimeouts.delete(roomId);
                        return;
                    }

                    // Only reset password if it wasn't pre-set
                    if (!room.isProtected) {
                        room.password = null;
                        room.isActive = false;
                    }
                    room.gameState = createInitialGameState();
                    room.chatHistory = []; // Clear chat history
                    ioInstance.emit('room_list', getRoomList());
                } else {
                    console.log(`Room ${roomId} has players again. Skipping reset.`);
                }
                
                roomTimeouts.delete(roomId);
            }, RECONNECT_GRACE_PERIOD);
            
            roomTimeouts.set(roomId, roomTimeoutId);
        }
    }
}

function getRoomList() {
    return Object.values(rooms)
        .filter(r => !r.isArchived) // Hide archived rooms from lobby
        .map(r => {
        // Check if room is actually active (has at least one player)
        const activePlayers = Object.values(r.players).filter(p => p !== null);
        const hasPlayers = activePlayers.length > 0;
        
        const roomData = {
            id: r.id,
            name: r.name,
            type: r.type,
            players: {
                red: r.players.red ? { name: r.players.red.name, joinedAt: r.players.red.joinedAt } : null,
                blue: r.players.blue ? { name: r.players.blue.name, joinedAt: r.players.blue.joinedAt } : null,
                green: r.players.green ? { name: r.players.green.name, joinedAt: r.players.green.joinedAt } : null,
                yellow: r.players.yellow ? { name: r.players.yellow.name, joinedAt: r.players.yellow.joinedAt } : null
            },
            playerCount: activePlayers.length,
            isActive: hasPlayers && r.isActive
        };
        
        if (r.type === 'public') {
            roomData.password = r.password;
        }
        
        return roomData;
    });
}

function getPublicPlayers(room) {
    return {
        red: room.players.red ? { name: room.players.red.name, status: room.players.red.status } : null,
        blue: room.players.blue ? { name: room.players.blue.name, status: room.players.blue.status } : null,
        green: room.players.green ? { name: room.players.green.name, status: room.players.green.status } : null,
        yellow: room.players.yellow ? { name: room.players.yellow.name, status: room.players.yellow.status } : null
    };
}

function getPlayerColor(room, socketId) {
    const colors = ['red', 'blue', 'green', 'yellow'];
    for (const color of colors) {
        if (room.players[color]?.id === socketId) return color;
    }
    return null;
}

function hasValidMoves(gameState, playerColor) {
    const pieces = gameState.board[playerColor];
    const dice = gameState.diceValue;
    
    for (let i = 0; i < 4; i++) {
        if (validateMove(gameState, playerColor, i, dice)) {
            return true;
        }
    }
    return false;
}

function validateMove(gameState, playerColor, pieceIndex, diceValue) {
    const pieces = gameState.board[playerColor];
    const position = pieces[pieceIndex];
    
    // Piece in home - needs 1 or 6 to come out
    if (position === -1) {
        return diceValue === 1 || diceValue === 6;
    }
    
    // Piece finished
    if (position === 100) {
        return false;
    }
    
    // Check if move is valid
    const newPos = position + diceValue;
    
    // In home stretch (52-57)
    if (position >= 52) {
        if (newPos > 57) return false; // Can't overshoot
        if (newPos === 57) {
            // Exact roll to finish
            return true;
        }
        return true;
    }
    
    // Normal board move
    if (newPos >= 52) {
        // Entering home stretch
        return true;
    }
    
    return true;
}

function applyMove(gameState, playerColor, pieceIndex, diceValue) {
    const pieces = gameState.board[playerColor];
    const position = pieces[pieceIndex];
    
    if (position === -1) {
        // Attempting to start
        if (diceValue === 1 || diceValue === 6) {
            pieces[pieceIndex] = getStartPosition(playerColor);
        }
    } else {
        // Moving an existing piece
        const currentSteps = getStepsFromPosition(playerColor, position);
        const targetSteps = currentSteps + diceValue;
        
        if (targetSteps <= 57) {
            // Valid move
            const newPosition = getPositionFromSteps(playerColor, targetSteps);
            pieces[pieceIndex] = newPosition;
            
            // Check for capture only if we are on the main track (steps < 52)
            // And not on a safe spot (though checkCapture handles safe spots usually)
            if (targetSteps < 52) {
                checkCapture(gameState, playerColor, newPosition);
            }
        }
        // If targetSteps > 57, move is invalid (overshoot), piece stays put
    }
    
    gameState.lastMove = { playerColor, pieceIndex, diceValue };
}

// Helper: Calculate logical steps taken from start (0-57) based on board position
function getStepsFromPosition(color, pos) {
    if (pos === -1) return -1; // In base
    if (pos === 100) return 57; // Finished
    
    // Home stretch positions (52-56) map to steps 52-56
    if (pos >= 52) return pos;
    
    // Main track positions (0-51)
    // We need to account for the player's start position
    const startPos = getStartPosition(color);
    
    // Calculate steps based on distance from start position
    // Handling the circular board (modulo 52)
    let steps;
    if (pos >= startPos) {
        steps = pos - startPos;
    } else {
        steps = (52 - startPos) + pos;
    }
    
    return steps;
}

// Helper: Calculate board position from logical steps (0-57)
function getPositionFromSteps(color, steps) {
    if (steps === -1) return -1;
    if (steps >= 57) return 100; // Finished
    if (steps >= 52) return steps; // Home stretch (mapped directly)
    
    // Main track (0-51)
    const startPos = getStartPosition(color);
    return (startPos + steps) % 52;
}

function getStartPosition(playerColor) {
    const starts = { red: 0, blue: 13, green: 26, yellow: 39 };
    return starts[playerColor];
}

function getHomeStretchEntry(playerColor) {
    // This function is kept for reference but logic is now handled by getPositionFromSteps
    const entries = { 
        red: 51,    // Red starts at 0, enters home at 51
        blue: 12,   // Blue starts at 13, enters home at 12
        green: 25,  // Green starts at 26, enters home at 25
        yellow: 38  // Yellow starts at 39, enters home at 38
    };
    return entries[playerColor];
}

function getStartPosition(playerColor) {
    const startPositions = { red: 0, blue: 13, green: 26, yellow: 39 };
    return startPositions[playerColor];
}

function checkCapture(gameState, playerColor, position) {
    // Safe spots - no capture allowed
    const safeSpots = [0, 8, 13, 21, 26, 34, 39, 47];
    if (safeSpots.includes(position)) return;

    const colors = ['red', 'blue', 'green', 'yellow'].filter(c => c !== playerColor);
    
    for (const color of colors) {
        const opponentPieces = gameState.board[color];
        for (let i = 0; i < 4; i++) {
            if (opponentPieces[i] === position && opponentPieces[i] < 52) {
                // Capture! Send opponent piece home
                opponentPieces[i] = -1;
            }
        }
    }
}

function checkWinCondition(gameState, playerColor) {
    const pieces = gameState.board[playerColor];
    return pieces.every(p => p === 100);
}

function nextTurn(room, ioInstance, roomId) {
    const gameState = room.gameState;
    
    if (!gameState.extraTurn) {
        // Move to next active player who hasn't finished yet
        const colors = ['red', 'blue', 'green', 'yellow'];
        const finishedColors = gameState.rankings.map(r => r.color);
        const activePlayers = colors.filter(c => room.players[c] !== null && !finishedColors.includes(c));
        
        if (activePlayers.length > 0) {
            const currentIndex = activePlayers.indexOf(gameState.currentTurn);
            
            // If current player is not in active list (just finished), start from next color
            if (currentIndex === -1) {
                // Find the next color after the current one
                const allColors = ['red', 'blue', 'green', 'yellow'];
                const currentColorIndex = allColors.indexOf(gameState.currentTurn);
                
                // Find next active player starting from current position
                for (let i = 1; i <= allColors.length; i++) {
                    const nextColorIndex = (currentColorIndex + i) % allColors.length;
                    const nextColor = allColors[nextColorIndex];
                    if (activePlayers.includes(nextColor)) {
                        gameState.currentTurn = nextColor;
                        break;
                    }
                }
            } else {
                // Normal rotation within active players
                const nextIndex = (currentIndex + 1) % activePlayers.length;
                gameState.currentTurn = activePlayers[nextIndex];
            }
        }
    }
    
    gameState.diceValue = null;
    gameState.extraTurn = false;
    
    ioInstance.to(roomId).emit('update_game', { gameState });
}
