// /server_modules/gameManager.js
const { v4: uuidv4 } = require('uuid');
const GameInstance = require('./gameInstance');
const gameData = require('./data');
const GAME_CONFIG = require('./config');

class GameManager {
    constructor(io) {
        this.io = io;
        this.games = {}; // { gameId: GameInstance }
        this.userIdentifierToGameId = {}; // { userId|socketId: gameId }
        this.pendingPvPGames = []; // [gameId]
    }

    _removePreviousPendingGames(currentSocketId, identifier, excludeGameId = null) {
        const oldPendingGameId = this.userIdentifierToGameId[identifier];
        if (oldPendingGameId && oldPendingGameId !== excludeGameId && this.games[oldPendingGameId]) {
            const gameToRemove = this.games[oldPendingGameId];
            if (gameToRemove.mode === 'pvp' && gameToRemove.playerCount === 1 && this.pendingPvPGames.includes(oldPendingGameId)) {
                const oldOwnerInfo = Object.values(gameToRemove.players).find(p => p.id === GAME_CONFIG.PLAYER_ID);
                if (oldOwnerInfo && (oldOwnerInfo.identifier === identifier)) {
                    console.log(`[GameManager] Пользователь ${identifier} (сокет: ${currentSocketId}) создал/присоединился к новой игре. Удаляем его предыдущую ожидающую игру: ${oldPendingGameId}`);
                    this._cleanupGame(oldPendingGameId, 'replaced_by_new_game');
                }
            } else {
                if (this.userIdentifierToGameId[identifier] !== excludeGameId) {
                    console.warn(`[GameManager] Удаление потенциально некорректной ссылки userIdentifierToGameId[${identifier}] на игру ${oldPendingGameId}.`);
                    delete this.userIdentifierToGameId[identifier];
                }
            }
        }
    }

    createGame(socket, mode = 'ai', chosenCharacterKey = 'elena', identifier) {
        this._removePreviousPendingGames(socket.id, identifier);
        if (this.userIdentifierToGameId[identifier] && this.games[this.userIdentifierToGameId[identifier]]) {
            console.warn(`[GameManager] Пользователь ${identifier} (сокет: ${socket.id}) уже в игре ${this.userIdentifierToGameId[identifier]}. Игнорируем запрос на создание.`);
            socket.emit('gameError', { message: 'Вы уже находитесь в активной или ожидающей игре.' });
            this.handleRequestGameState(socket, identifier);
            return;
        }

        const gameId = uuidv4();
        const game = new GameInstance(gameId, this.io, mode, this);
        game.ownerIdentifier = identifier;
        this.games[gameId] = game;
        const charKeyForInstance = (mode === 'pvp') ? chosenCharacterKey : 'elena';

        if (game.addPlayer(socket, charKeyForInstance, identifier)) {
            this.userIdentifierToGameId[identifier] = gameId;
            console.log(`[GameManager] Игра создана: ${gameId} (режим: ${mode}) игроком ${identifier} (сокет: ${socket.id}, выбран: ${charKeyForInstance})`);
            const assignedPlayerId = game.players[socket.id]?.id;
            if (!assignedPlayerId) {
                this._cleanupGame(gameId, 'player_add_failed');
                console.error(`[GameManager] Ошибка при создании игры ${gameId}: Не удалось назначить ID игрока сокету ${socket.id} (идентификатор ${identifier}).`);
                socket.emit('gameError', { message: 'Ошибка сервера при создании игры.' });
                return;
            }
            socket.emit('gameCreated', { gameId: gameId, mode: mode, yourPlayerId: assignedPlayerId });

            if ((game.mode === 'ai' && game.playerCount === 1) || (game.mode === 'pvp' && game.playerCount === 2)) {
                console.log(`[GameManager] Игра ${gameId} готова к старту. Инициализация и запуск.`);
                const isInitialized = game.initializeGame();
                if (isInitialized) {
                    game.startGame();
                } else {
                    console.error(`[GameManager] Не удалось запустить игру ${gameId}: initializeGame вернул false или gameState некорректен после инициализации.`);
                    this._cleanupGame(gameId, 'initialization_failed');
                }
                if (game.mode === 'pvp' && game.playerCount === 2) {
                    const gameIndex = this.pendingPvPGames.indexOf(gameId);
                    if (gameIndex > -1) this.pendingPvPGames.splice(gameIndex, 1);
                    this.broadcastAvailablePvPGames();
                }
            } else if (mode === 'pvp' && game.playerCount === 1) {
                if (!this.pendingPvPGames.includes(gameId)) {
                    this.pendingPvPGames.push(gameId);
                }
                game.initializeGame(); // Частичная инициализация
                this.broadcastAvailablePvPGames();
            }
        } else {
            this._cleanupGame(gameId, 'player_add_failed');
            console.warn(`[GameManager] Не удалось добавить игрока ${socket.id} (идентификатор ${identifier}) в игру ${gameId}. Игра удалена.`);
        }
    }

    joinGame(socket, gameId, identifier) {
        const game = this.games[gameId];
        if (!game) { socket.emit('gameError', { message: 'Игра с таким ID не найдена.' }); return; }
        if (game.mode !== 'pvp') { socket.emit('gameError', { message: 'К этой игре нельзя присоединиться как к PvP.' }); return; }
        if (game.playerCount >= 2) { socket.emit('gameError', { message: 'Эта PvP игра уже заполнена.' }); return; }
        if (this.userIdentifierToGameId[identifier] && this.games[this.userIdentifierToGameId[identifier]] && this.userIdentifierToGameId[identifier] !== gameId) {
            console.warn(`[GameManager] Пользователь ${identifier} (сокет: ${socket.id}) уже в игре ${this.userIdentifierToGameId[identifier]}. Игнорируем запрос на присоединение.`);
            socket.emit('gameError', { message: 'Вы уже находитесь в активной или ожидающей игре.' });
            this.handleRequestGameState(socket, identifier);
            return;
        }
        if (game.players[socket.id]) { socket.emit('gameError', { message: 'Вы уже в этой игре.' }); return; }

        this._removePreviousPendingGames(socket.id, identifier, gameId);

        if (game.addPlayer(socket, null, identifier)) {
            this.userIdentifierToGameId[identifier] = gameId;
            console.log(`[GameManager] Игрок ${identifier} (сокет: ${socket.id}) присоединился к PvP игре ${gameId}`);
            if (game.mode === 'pvp' && game.playerCount === 2) {
                console.log(`[GameManager] Игра ${gameId} готова к старту. Инициализация и запуск.`);
                const isInitialized = game.initializeGame();
                if (isInitialized) {
                    game.startGame();
                } else {
                    console.error(`[GameManager] Не удалось запустить игру ${gameId}: initializeGame вернул false или gameState некорректен после инициализации.`);
                    this._cleanupGame(gameId, 'initialization_failed');
                }
                const gameIndex = this.pendingPvPGames.indexOf(gameId);
                if (gameIndex > -1) this.pendingPvPGames.splice(gameIndex, 1);
                this.broadcastAvailablePvPGames();
            }
        } else {
            console.warn(`[GameManager] Не удалось добавить игрока ${socket.id} (идентификатор ${identifier}) в игру ${gameId}.`);
        }
    }

    findAndJoinRandomPvPGame(socket, chosenCharacterKeyForCreation = 'elena', identifier) {
        this._removePreviousPendingGames(socket.id, identifier);
        if (this.userIdentifierToGameId[identifier] && this.games[this.userIdentifierToGameId[identifier]]) {
            console.warn(`[GameManager] Пользователь ${identifier} (сокет: ${socket.id}) уже в игре ${this.userIdentifierToGameId[identifier]}. Игнорируем запрос на поиск.`);
            socket.emit('gameError', { message: 'Вы уже находитесь в активной или ожидающей игре.' });
            this.handleRequestGameState(socket, identifier);
            return;
        }

        let gameIdToJoin = null;
        const preferredOpponentKey = chosenCharacterKeyForCreation === 'elena' ? 'almagest' : 'elena';

        for (const id of this.pendingPvPGames) {
            const pendingGame = this.games[id];
            if (pendingGame && pendingGame.mode === 'pvp' && pendingGame.playerCount === 1 && pendingGame.ownerIdentifier !== identifier) {
                const firstPlayerInfo = Object.values(pendingGame.players).find(p => p.id === GAME_CONFIG.PLAYER_ID);
                if (firstPlayerInfo && firstPlayerInfo.chosenCharacterKey === preferredOpponentKey) {
                    gameIdToJoin = id;
                    break;
                }
                if (!gameIdToJoin) gameIdToJoin = id;
            }
        }

        if (gameIdToJoin) {
            console.log(`[GameManager] Игрок ${identifier} (сокет: ${socket.id}) нашел игру ${gameIdToJoin} и присоединяется.`);
            this.joinGame(socket, gameIdToJoin, identifier);
        } else {
            console.log(`[GameManager] Игрок ${identifier} (сокет: ${socket.id}) не нашел свободных игр. Создает новую.`);
            this.createGame(socket, 'pvp', chosenCharacterKeyForCreation, identifier);
            socket.emit('noPendingGamesFound', {
                message: 'Свободных PvP игр не найдено. Создана новая игра для вас. Ожидайте противника.',
                gameId: this.userIdentifierToGameId[identifier],
                yourPlayerId: GAME_CONFIG.PLAYER_ID
            });
        }
    }

    handlePlayerAction(identifier, actionData) {
        const gameId = this.userIdentifierToGameId[identifier];
        const game = this.games[gameId];
        if (game && game.players) {
            const playerInfo = Object.values(game.players).find(p => p.identifier === identifier);
            const currentSocketId = playerInfo?.socket?.id;
            if (playerInfo && currentSocketId) {
                const actualSocket = this.io.sockets.sockets.get(currentSocketId);
                if (actualSocket && actualSocket.connected) {
                    game.processPlayerAction(currentSocketId, actionData);
                } else {
                    console.warn(`[GameManager] Игрок ${identifier} отправил действие (${actionData?.actionType}), но его текущий сокет (${currentSocketId}) не найден или отключен.`);
                }
            } else {
                console.warn(`[GameManager] Игрок ${identifier} отправил действие (${actionData?.actionType}) для игры ${gameId}, но его запись не найдена в game.players.`);
                delete this.userIdentifierToGameId[identifier];
                const playerSocket = this.io.sockets.sockets.get(identifier) || playerInfo?.socket;
                if (playerSocket) {
                    playerSocket.emit('gameNotFound', { message: 'Ваша игровая сессия не найдена или завершена.' });
                }
            }
        } else {
            console.warn(`[GameManager] Игрок ${identifier} отправил действие (${actionData?.actionType}), но его игра (ID: ${gameId}) не найдена в GameManager.`);
            delete this.userIdentifierToGameId[identifier];
            const playerSocket = this.io.sockets.sockets.get(identifier);
            if (playerSocket) {
                playerSocket.emit('gameNotFound', { message: 'Ваша игровая сессия не найдена или завершена.' });
            }
        }
    }

    handleDisconnect(socketId, identifier) {
        const gameId = this.userIdentifierToGameId[identifier];
        const game = this.games[gameId];

        if (game && game.players) {
            const playerInfo = Object.values(game.players).find(p => p.identifier === identifier);
            if (playerInfo) {
                console.log(`[GameManager] Игрок ${identifier} (сокет: ${socketId}) отключился. В игре ${gameId}.`);
                const disconnectedPlayerRole = playerInfo.id;
                const disconnectedCharacterKey = playerInfo.chosenCharacterKey;

                game.removePlayer(socketId); // Удаляем именно этот сокет

                if (game.playerCount === 0) {
                    console.log(`[GameManager] Игра ${gameId} пуста после дисконнекта ${socketId} (идентификатор ${identifier}). Удаляем.`);
                    this._cleanupGame(gameId, 'player_count_zero_on_disconnect');
                } else if (game.mode === 'pvp' && game.playerCount === 1 && game.gameState && !game.gameState.isGameOver) {
                    // Если это PvP игра и остался 1 игрок, и игра НЕ была завершена дисконнектом этого игрока
                    // (т.е. другой игрок еще в игре)
                    // Тогда игра переходит в состояние ожидания.
                    const remainingPlayerInfo = Object.values(game.players)[0]; // Единственный оставшийся игрок
                    if (remainingPlayerInfo) {
                        // Проверяем, что это не тот же игрок, что и отключившийся
                        if (remainingPlayerInfo.identifier !== identifier) {
                            game.endGameDueToDisconnect(socketId, disconnectedPlayerRole, disconnectedCharacterKey);
                            // _cleanupGame будет вызван из endGameDueToDisconnect
                        } else {
                            // Отключился единственный оставшийся игрок в ожидающей игре.
                            // _cleanupGame должен быть вызван.
                            console.log(`[GameManager] Отключился единственный игрок ${identifier} из ожидающей PvP игры ${gameId}. Удаляем игру.`);
                            this._cleanupGame(gameId, 'last_player_disconnected_from_pending');
                        }
                    } else {
                        // Оставшегося игрока нет, хотя playerCount > 0 - это ошибка, очищаем.
                        console.error(`[GameManager] Ошибка: playerCount > 0 в игре ${gameId}, но не найден оставшийся игрок после дисконнекта ${identifier}. Очищаем.`);
                        this._cleanupGame(gameId, 'error_no_remaining_player');
                    }
                } else if (game.gameState && !game.gameState.isGameOver) {
                    // Если игра была активна (не ожидала) и еще не была завершена,
                    // дисконнект одного из игроков завершает игру.
                    game.endGameDueToDisconnect(socketId, disconnectedPlayerRole, disconnectedCharacterKey);
                    // _cleanupGame будет вызван из endGameDueToDisconnect
                } else if (game.gameState?.isGameOver) {
                    // Если игра уже была завершена до этого дисконнекта, просто удаляем ссылку на игру для отключившегося.
                    console.log(`[GameManager] Игрок ${identifier} отключился из уже завершенной игры ${gameId}. Удаляем ссылку.`);
                    delete this.userIdentifierToGameId[identifier];
                    // _cleanupGame уже был вызван при завершении игры.
                } else {
                    // Другие случаи (например, AI игра, где игрок остался, или ошибка)
                    console.log(`[GameManager] Игрок ${identifier} отключился из активной игры ${gameId} (mode: ${game.mode}, players: ${game.playerCount}). Удаляем ссылку.`);
                    delete this.userIdentifierToGameId[identifier];
                }
            } else {
                console.warn(`[GameManager] Игрок с идентификатором ${identifier} (сокет: ${socketId}) не найден в game.players для игры ${gameId}.`);
                delete this.userIdentifierToGameId[identifier];
            }
        } else {
            console.log(`[GameManager] Отключился сокет ${socketId} (идентификатор ${identifier}). Игровая сессия по этому идентификатору не найдена.`);
            delete this.userIdentifierToGameId[identifier];
        }
    }

    _cleanupGame(gameId, reason = 'unknown_reason') {
        const game = this.games[gameId];
        if (!game) {
            console.warn(`[GameManager] _cleanupGame called for unknown game ID: ${gameId}`);
            return false;
        }

        console.log(`[GameManager] Cleaning up game ${gameId} (Mode: ${game.mode}, Reason: ${reason})...`);

        // Очищаем таймеры, если они были активны
        if (typeof game.clearTurnTimer === 'function') {
            game.clearTurnTimer();
        }

        Object.values(game.players).forEach(playerInfo => {
            if (playerInfo && playerInfo.identifier && this.userIdentifierToGameId[playerInfo.identifier] === gameId) {
                delete this.userIdentifierToGameId[playerInfo.identifier];
                console.log(`[GameManager] Removed userIdentifierToGameId for ${playerInfo.identifier}.`);
            }
        });

        const pendingIndex = this.pendingPvPGames.indexOf(gameId);
        if (pendingIndex > -1) {
            this.pendingPvPGames.splice(pendingIndex, 1);
            console.log(`[GameManager] Removed game ${gameId} from pendingPvPGames.`);
        }

        delete this.games[gameId];
        console.log(`[GameManager] Deleted GameInstance for game ${gameId}.`);
        this.broadcastAvailablePvPGames();
        return true;
    }

    getAvailablePvPGamesListForClient() {
        return this.pendingPvPGames
            .map(gameId => {
                const game = this.games[gameId];
                if (game && game.mode === 'pvp' && game.playerCount === 1 && game.gameState && !game.gameState.isGameOver) {
                    let firstPlayerUsername = 'Игрок';
                    let firstPlayerCharacterName = '';
                    const firstPlayerInfo = Object.values(game.players).find(p => p.id === GAME_CONFIG.PLAYER_ID);

                    if (firstPlayerInfo) {
                        if (firstPlayerInfo.socket?.userData?.username) {
                            firstPlayerUsername = firstPlayerInfo.socket.userData.username;
                        } else {
                            firstPlayerUsername = `User#${String(firstPlayerInfo.identifier).substring(0, 6)}`;
                        }
                        const charKey = firstPlayerInfo.chosenCharacterKey;
                        if (charKey) {
                            const charBaseStats = this._getCharacterBaseData(charKey);
                            if (charBaseStats && charBaseStats.name) {
                                firstPlayerCharacterName = charBaseStats.name;
                            } else {
                                firstPlayerCharacterName = charKey;
                            }
                        }
                    } else {
                        console.warn(`[GameManager] getAvailablePvPGamesList: firstPlayerInfo (Player 1) не найдена для ожидающей игры ${gameId}.`);
                        firstPlayerUsername = 'Неизвестный игрок';
                    }
                    let statusString = `Ожидает 1 игрока (Создал: ${firstPlayerUsername}`;
                    if (firstPlayerCharacterName) statusString += ` за ${firstPlayerCharacterName}`;
                    statusString += `)`;
                    return { id: gameId, status: statusString };
                }
                if (game && !this.pendingPvPGames.includes(gameId)) { /* Game not pending */ }
                else if (game && game.playerCount === 1 && (game.gameState?.isGameOver || !game.gameState)) { /* Game over or not initialized */ }
                else if (game && game.playerCount === 2) { /* Game full */ }
                else if (game && game.playerCount === 0) {
                    console.warn(`[GameManager] getAvailablePvPGamesList: Найдена пустая игра ${gameId} в games. Удаляем.`);
                    delete this.games[gameId];
                }
                return null;
            })
            .filter(info => info !== null);
    }

    broadcastAvailablePvPGames() {
        const availableGames = this.getAvailablePvPGamesListForClient();
        this.io.emit('availablePvPGamesList', availableGames);
        console.log(`[GameManager] Обновлен список доступных PvP игр. Всего: ${availableGames.length}`);
    }

    getActiveGamesList() {
        return Object.values(this.games).map(game => {
            let playerSlotCharName = game.gameState?.player?.name || (game.playerCharacterKey ? this._getCharacterBaseData(game.playerCharacterKey)?.name : 'N/A (ожидание)');
            let opponentSlotCharName = game.gameState?.opponent?.name || (game.opponentCharacterKey ? this._getCharacterBaseData(game.opponentCharacterKey)?.name : 'N/A (ожидание)');
            const playerInSlot1 = Object.values(game.players).find(p => p.id === GAME_CONFIG.PLAYER_ID);
            const playerInSlot2 = Object.values(game.players).find(p => p.id === GAME_CONFIG.OPPONENT_ID);

            if (!playerInSlot1) playerSlotCharName = 'Пусто';
            if (!playerInSlot2 && game.mode === 'pvp') opponentSlotCharName = 'Ожидание...';
            if (!playerInSlot2 && game.mode === 'ai' && game.aiOpponent) opponentSlotCharName = 'Балард (AI)';

            return {
                id: game.id.substring(0, 8),
                mode: game.mode,
                playerCount: game.playerCount,
                isGameOver: game.gameState ? game.gameState.isGameOver : 'N/A (Не инициализирована)',
                playerSlot: playerSlotCharName,
                opponentSlot: opponentSlotCharName,
                ownerIdentifier: game.ownerIdentifier || 'N/A',
                pending: this.pendingPvPGames.includes(game.id),
                turn: game.gameState ? `Ход ${game.gameState.turnNumber}, ${game.gameState.isPlayerTurn ? (playerInSlot1?.identifier || 'Player Slot') : (playerInSlot2?.identifier || 'Opponent Slot')}` : 'N/A'
            };
        });
    }

    handleRequestGameState(socket, identifier) {
        const gameId = this.userIdentifierToGameId[identifier];
        let game = gameId ? this.games[gameId] : null;

        if (game && game.players) {
            const playerInfo = Object.values(game.players).find(p => p.identifier === identifier);
            if (playerInfo) {
                if (game.gameState?.isGameOver) {
                    console.log(`[GameManager] Reconnected user ${identifier} to game ${gameId} which is already over. Sending gameNotFound.`);
                    delete this.userIdentifierToGameId[identifier];
                    socket.emit('gameNotFound', { message: 'Ваша предыдущая игровая сессия уже завершена.' });
                    return;
                }

                console.log(`[GameManager] Found game ${gameId} for identifier ${identifier} (role ${playerInfo.id}). Reconnecting socket ${socket.id}.`);
                const oldSocketId = playerInfo.socket?.id;
                if (oldSocketId && oldSocketId !== socket.id && game.players[oldSocketId]) {
                    console.log(`[GameManager] Updating socket ID for player ${identifier} from ${oldSocketId} to ${socket.id} in game ${gameId}.`);
                    delete game.players[oldSocketId];
                    if (game.playerSockets[playerInfo.id]?.id === oldSocketId) {
                        delete game.playerSockets[playerInfo.id];
                    }
                }
                game.players[socket.id] = playerInfo;
                game.players[socket.id].socket = socket;
                game.playerSockets[playerInfo.id] = socket;
                socket.join(game.id);

                const playerCharDataForClient = this._getCharacterData(playerInfo.chosenCharacterKey);
                const opponentActualSlotId = playerInfo.id === GAME_CONFIG.PLAYER_ID ? GAME_CONFIG.OPPONENT_ID : GAME_CONFIG.PLAYER_ID;
                let opponentCharacterKeyForClient = game.gameState?.[opponentActualSlotId]?.characterKey || null;
                if (!opponentCharacterKeyForClient) {
                    opponentCharacterKeyForClient = playerInfo.id === GAME_CONFIG.PLAYER_ID ? game.opponentCharacterKey : game.playerCharacterKey;
                }
                const opponentCharDataForClient = this._getCharacterData(opponentCharacterKeyForClient);

                if (playerCharDataForClient && opponentCharDataForClient && game.gameState) {
                    const isGameReadyForPlay = (game.mode === 'ai' && game.playerCount === 1) || (game.mode === 'pvp' && game.playerCount === 2);
                    const isOpponentDefinedInState = game.gameState.opponent?.characterKey && game.gameState.opponent?.name !== 'Ожидание игрока...';

                    socket.emit('gameState', {
                        gameId: game.id, yourPlayerId: playerInfo.id, gameState: game.gameState,
                        playerBaseStats: playerCharDataForClient.baseStats, opponentBaseStats: opponentCharDataForClient.baseStats,
                        playerAbilities: playerCharDataForClient.abilities, opponentAbilities: opponentCharDataForClient.abilities,
                        log: game.consumeLogBuffer(), clientConfig: { ...GAME_CONFIG }
                    });
                    console.log(`[GameManager] Sent gameState to socket ${socket.id} (identifier: ${identifier}) for game ${game.id}.`);

                    if (!game.gameState.isGameOver && isGameReadyForPlay && !isOpponentDefinedInState) {
                        console.log(`[GameManager] Game ${game.id} found ready but not fully started on reconnect. Initializing/Starting.`);
                        const isInitialized = game.initializeGame();
                        if (isInitialized) {
                            game.startGame();
                        } else {
                            console.error(`[GameManager] Failed to initialize game ${game.id} on reconnect. Cannot start.`);
                            this.io.to(game.id).emit('gameError', { message: 'Ошибка сервера при старте игры после переподключения.' });
                            this._cleanupGame(gameId, 'reconnect_initialization_failed');
                        }
                    } else if (!isGameReadyForPlay) {
                        console.log(`[GameManager] Reconnected user ${identifier} to pending game ${gameId}. Sending gameState and waiting status.`);
                        socket.emit('waitingForOpponent');
                    } else if (game.gameState.isGameOver) { // Повторная проверка, т.к. startGame мог завершить игру
                        console.log(`[GameManager] Reconnected to game ${gameId} which is now over (after re-init). Sending gameNotFound.`);
                        delete this.userIdentifierToGameId[identifier];
                        socket.emit('gameNotFound', { message: 'Ваша игровая сессия завершилась во время переподключения.' });
                    } else {
                        console.log(`[GameManager] Reconnected user ${identifier} to active game ${gameId}. gameState sent.`);
                        // Важно: если игра активна, нужно отправить и текущее состояние таймера.
                        // Это можно сделать, вызвав game.startTurnTimer() (он отправит update),
                        // но только если это ход этого игрока и игра не AI (или ход игрока в AI).
                        // Или добавить отдельный метод в GameInstance для отправки текущего состояния таймера.
                        if (typeof game.startTurnTimer === 'function') { // Проверяем, что метод существует
                            // Перезапуск таймера здесь может быть некорректным, если ход не этого игрока
                            // Лучше, чтобы gameInstance сам отправлял 'turnTimerUpdate' при gameState
                            // Либо добавить специальный метод в gameInstance для отправки текущего значения таймера
                            // Пока оставим так, startTurnTimer сам проверит, чей ход.
                            game.startTurnTimer();
                        }
                    }
                } else {
                    console.error(`[GameManager] Failed to send gameState to ${socket.id} (identifier ${identifier}) for game ${gameId}: missing character data or gameState.`);
                    socket.emit('gameError', { message: 'Ошибка сервера при восстановлении состояния игры.' });
                    this._cleanupGame(gameId, 'reconnect_send_failed');
                    socket.emit('gameNotFound', { message: 'Ваша игровая сессия в некорректном состоянии и была завершена.' });
                }
            } else {
                console.warn(`[GameManager] Found game ${gameId} by identifier ${identifier}, but player with this identifier not found in game.players.`);
                delete this.userIdentifierToGameId[identifier];
                socket.emit('gameNotFound', { message: 'Ваша игровая сессия не найдена. Возможно, идентификатор пользователя некорректен.' });
            }
        } else {
            console.log(`[GameManager] No active or pending game found for identifier ${identifier}.`);
            socket.emit('gameNotFound', { message: 'Игровая сессия не найдена.' });
        }
    }

    _getCharacterData(key) {
        if (!key) { console.warn("GameManager::_getCharacterData called with null/undefined key."); return null; }
        switch (key) {
            case 'elena': return { baseStats: gameData.playerBaseStats, abilities: gameData.playerAbilities };
            case 'balard': return { baseStats: gameData.opponentBaseStats, abilities: gameData.opponentAbilities };
            case 'almagest': return { baseStats: gameData.almagestBaseStats, abilities: gameData.almagestAbilities };
            default: console.error(`GameManager::_getCharacterData: Unknown character key "${key}"`); return null;
        }
    }
    _getCharacterBaseData(key) {
        const charData = this._getCharacterData(key);
        return charData ? charData.baseStats : null;
    }
    _getCharacterAbilities(key) {
        const charData = this._getCharacterData(key);
        return charData ? charData.abilities : null;
    }
}

module.exports = GameManager;