// /server/game/instance/GameInstance.js
const { v4: uuidv4 } = require('uuid');
const TurnTimer = require('./TurnTimer');
const gameLogic = require('../logic'); // Импортирует index.js из папки logic
const dataUtils = require('../../data/dataUtils');
const GAME_CONFIG = require('../../core/config'); // <--- УБЕДИТЕСЬ, ЧТО GAME_CONFIG ИМПОРТИРОВАН

class GameInstance {
    constructor(gameId, io, mode = 'ai', gameManager) {
        this.id = gameId;
        this.io = io;
        this.mode = mode;
        this.players = {};
        this.playerSockets = {};
        this.playerCount = 0;
        this.gameState = null;
        this.aiOpponent = (mode === 'ai');
        this.logBuffer = [];
        this.playerCharacterKey = null;
        this.opponentCharacterKey = null;
        this.ownerIdentifier = null;
        this.gameManager = gameManager;

        this.turnTimer = new TurnTimer(
            GAME_CONFIG.TURN_DURATION_MS,
            GAME_CONFIG.TIMER_UPDATE_INTERVAL_MS,
            () => this.handleTurnTimeout(),
            (remainingTime, isPlayerTurnForTimer) => {
                this.io.to(this.id).emit('turnTimerUpdate', { remainingTime, isPlayerTurn: isPlayerTurnForTimer });
            }
        );

        if (!this.gameManager || typeof this.gameManager._cleanupGame !== 'function') {
            console.error(`[GameInstance ${this.id}] CRITICAL ERROR: GameManager reference invalid.`);
        }
        console.log(`[GameInstance ${this.id}] Created. Mode: ${mode}.`);
    }

    addPlayer(socket, chosenCharacterKey = 'elena', identifier) {
        if (this.players[socket.id]) {
            socket.emit('gameError', { message: 'Ваш сокет уже зарегистрирован в этой игре.' });
            return false;
        }
        const existingPlayerByIdentifier = Object.values(this.players).find(p => p.identifier === identifier);
        if (existingPlayerByIdentifier) {
            socket.emit('gameError', { message: 'Вы уже находитесь в этой игре под другим подключением.' });
            return false;
        }
        if (this.playerCount >= 2) {
            socket.emit('gameError', { message: 'Эта игра уже заполнена.' });
            return false;
        }

        let assignedPlayerId;
        let actualCharacterKey;

        if (this.mode === 'ai') {
            if (this.playerCount > 0) {
                socket.emit('gameError', { message: 'Нельзя присоединиться к AI игре как второй игрок.' });
                return false;
            }
            assignedPlayerId = GAME_CONFIG.PLAYER_ID;
            actualCharacterKey = 'elena';
            this.ownerIdentifier = identifier;
        } else { // PvP
            if (this.playerCount === 0) {
                assignedPlayerId = GAME_CONFIG.PLAYER_ID;
                actualCharacterKey = (chosenCharacterKey === 'almagest') ? 'almagest' : 'elena';
                this.ownerIdentifier = identifier;
            } else {
                assignedPlayerId = GAME_CONFIG.OPPONENT_ID;
                const firstPlayerInfo = Object.values(this.players).find(p => p.id === GAME_CONFIG.PLAYER_ID);
                actualCharacterKey = (firstPlayerInfo?.chosenCharacterKey === 'elena') ? 'almagest' : 'elena';
            }
        }

        this.players[socket.id] = {
            id: assignedPlayerId, socket: socket,
            chosenCharacterKey: actualCharacterKey, identifier: identifier
        };
        this.playerSockets[assignedPlayerId] = socket;
        this.playerCount++;
        socket.join(this.id);

        const characterBaseStats = dataUtils.getCharacterBaseStats(actualCharacterKey);
        console.log(`[GameInstance ${this.id}] Игрок ${identifier} (сокет ${socket.id}) (${characterBaseStats?.name || 'N/A'}) присоединился как ${assignedPlayerId} (персонаж: ${actualCharacterKey}). Игроков: ${this.playerCount}.`);
        return true;
    }

    removePlayer(socketId) {
        const playerInfo = this.players[socketId];
        if (playerInfo) {
            const playerRole = playerInfo.id;
            console.log(`[GameInstance ${this.id}] Игрок ${playerInfo.identifier} (сокет: ${socketId}, роль: ${playerRole}) покинул игру.`);
            if (playerInfo.socket) { try { playerInfo.socket.leave(this.id); } catch (e) { /* ignore */ } }
            delete this.players[socketId];
            this.playerCount--;
            if (this.playerSockets[playerRole]?.id === socketId) {
                delete this.playerSockets[playerRole];
            }
            if (this.gameState && !this.gameState.isGameOver) {
                const isTurnOfDisconnected = (this.gameState.isPlayerTurn && playerRole === GAME_CONFIG.PLAYER_ID) ||
                    (!this.gameState.isPlayerTurn && playerRole === GAME_CONFIG.OPPONENT_ID);
                if (isTurnOfDisconnected) this.turnTimer.clear();
            }
        }
    }

    initializeGame() {
        console.log(`[GameInstance ${this.id}] Инициализация состояния игры. Режим: ${this.mode}. Игроков: ${this.playerCount}.`);
        if (this.mode === 'ai' && this.playerCount === 1) {
            this.playerCharacterKey = 'elena'; this.opponentCharacterKey = 'balard';
        } else if (this.mode === 'pvp' && this.playerCount === 2) {
            const p1Info = Object.values(this.players).find(p => p.id === GAME_CONFIG.PLAYER_ID);
            this.playerCharacterKey = p1Info?.chosenCharacterKey || 'elena';
            this.opponentCharacterKey = (this.playerCharacterKey === 'elena') ? 'almagest' : 'elena';
        } else if (this.mode === 'pvp' && this.playerCount === 1) {
            const p1Info = Object.values(this.players).find(p => p.id === GAME_CONFIG.PLAYER_ID);
            this.playerCharacterKey = p1Info?.chosenCharacterKey || 'elena';
            this.opponentCharacterKey = null;
        } else {
            console.error(`[GameInstance ${this.id}] Некорректное состояние для инициализации!`); return false;
        }

        const playerData = dataUtils.getCharacterData(this.playerCharacterKey);
        let opponentData = null;
        const isOpponentDefined = !!this.opponentCharacterKey;
        if (isOpponentDefined) opponentData = dataUtils.getCharacterData(this.opponentCharacterKey);

        if (!playerData || (isOpponentDefined && !opponentData)) {
            this._handleCriticalError('init_char_data_fail', 'Ошибка загрузки данных персонажей при инициализации.');
            return false;
        }
        if (isOpponentDefined && (!opponentData.baseStats.maxHp || opponentData.baseStats.maxHp <= 0)) {
            this._handleCriticalError('init_opponent_hp_fail', 'Некорректные HP оппонента при инициализации.');
            return false;
        }

        this.gameState = {
            player: this._createFighterState(GAME_CONFIG.PLAYER_ID, playerData.baseStats, playerData.abilities),
            opponent: isOpponentDefined ?
                this._createFighterState(GAME_CONFIG.OPPONENT_ID, opponentData.baseStats, opponentData.abilities) :
                this._createFighterState(GAME_CONFIG.OPPONENT_ID, { name: 'Ожидание игрока...', maxHp: 1, maxResource: 0, resourceName: 'Ресурс', attackPower: 0, characterKey: null }, []), // Плейсхолдер
            isPlayerTurn: isOpponentDefined ? Math.random() < 0.5 : true,
            isGameOver: false, turnNumber: 1, gameMode: this.mode
        };

        if (isOpponentDefined) {
            this.logBuffer = [];
            this.addToLog('⚔️ Новая битва начинается! ⚔️', GAME_CONFIG.LOG_TYPE_SYSTEM);
            const pCharKey = this.gameState.player.characterKey;
            const oCharKey = this.gameState.opponent.characterKey; // Нужен ключ оппонента для контекста
            if ((pCharKey === 'elena' || pCharKey === 'almagest') && oCharKey) {
                const opponentFullDataForTaunt = dataUtils.getCharacterData(oCharKey); // Получаем полные данные оппонента
                const startTaunt = gameLogic.getRandomTaunt(pCharKey, 'battleStart', {}, GAME_CONFIG, opponentFullDataForTaunt, this.gameState);
                if (startTaunt !== "(Молчание)") this.addToLog(`${this.gameState.player.name}: "${startTaunt}"`, GAME_CONFIG.LOG_TYPE_INFO);
            }
        }
        console.log(`[GameInstance ${this.id}] Состояние игры инициализировано. Готовность к старту: ${isOpponentDefined}`);
        return isOpponentDefined;
    }

    _createFighterState(roleId, baseStats, abilities) {
        const fighterState = {
            id: roleId, characterKey: baseStats.characterKey, name: baseStats.name,
            currentHp: baseStats.maxHp, maxHp: baseStats.maxHp,
            currentResource: baseStats.maxResource, maxResource: baseStats.maxResource,
            resourceName: baseStats.resourceName, attackPower: baseStats.attackPower,
            isBlocking: false, activeEffects: [], disabledAbilities: [], abilityCooldowns: {}
        };
        (abilities || []).forEach(ability => { // Добавлена проверка abilities
            if (typeof ability.cooldown === 'number' && ability.cooldown >= 0) {
                fighterState.abilityCooldowns[ability.id] = 0;
            }
        });
        if (baseStats.characterKey === 'balard') {
            fighterState.silenceCooldownTurns = 0;
            fighterState.manaDrainCooldownTurns = 0;
        }
        return fighterState;
    }

    startGame() {
        if (!this.gameState || !this.gameState.opponent?.characterKey) {
            this._handleCriticalError('start_game_not_ready', 'Попытка старта не полностью готовой игры.');
            return;
        }
        console.log(`[GameInstance ${this.id}] Запуск игры.`);

        const pData = dataUtils.getCharacterData(this.playerCharacterKey);
        const oData = dataUtils.getCharacterData(this.opponentCharacterKey);
        if (!pData || !oData) { this._handleCriticalError('start_char_data_fail', 'Ошибка данных персонажей при старте.'); return; }

        Object.values(this.players).forEach(playerInfo => {
            if (playerInfo.socket?.connected) {
                const dataForClient = playerInfo.id === GAME_CONFIG.PLAYER_ID ?
                    { playerBaseStats: pData.baseStats, opponentBaseStats: oData.baseStats, playerAbilities: pData.abilities, opponentAbilities: oData.abilities } :
                    { playerBaseStats: oData.baseStats, opponentBaseStats: pData.baseStats, playerAbilities: oData.abilities, opponentAbilities: pData.abilities };
                playerInfo.socket.emit('gameStarted', {
                    gameId: this.id, yourPlayerId: playerInfo.id, initialGameState: this.gameState,
                    ...dataForClient, log: this.consumeLogBuffer(), clientConfig: { ...GAME_CONFIG }
                });
            }
        });

        const firstTurnActor = this.gameState.isPlayerTurn ? this.gameState.player : this.gameState.opponent;
        this.addToLog(`--- Начинается ход ${this.gameState.turnNumber} для: ${firstTurnActor.name} ---`, GAME_CONFIG.LOG_TYPE_TURN);
        this.broadcastLogUpdate();
        this.turnTimer.start(this.gameState.isPlayerTurn, (this.mode === 'ai' && !this.gameState.isPlayerTurn));

        if (!this.gameState.isPlayerTurn && this.aiOpponent) {
            setTimeout(() => this.processAiTurn(), GAME_CONFIG.DELAY_OPPONENT_TURN);
        }
    }

    processPlayerAction(requestingSocketId, actionData) {
        if (!this.gameState || this.gameState.isGameOver) return;
        const actingPlayerInfo = this.players[requestingSocketId];
        if (!actingPlayerInfo) { console.error(`[GameInstance ${this.id}] Действие от неизвестного сокета ${requestingSocketId}`); return; }

        const actingPlayerRole = actingPlayerInfo.id;
        const isCorrectTurn = (this.gameState.isPlayerTurn && actingPlayerRole === GAME_CONFIG.PLAYER_ID) ||
            (!this.gameState.isPlayerTurn && actingPlayerRole === GAME_CONFIG.OPPONENT_ID);
        if (!isCorrectTurn) { console.warn(`[GameInstance ${this.id}] Действие от ${actingPlayerInfo.identifier}: не его ход.`); return; }

        this.turnTimer.clear();

        const attackerState = this.gameState[actingPlayerRole];
        const defenderRole = actingPlayerRole === GAME_CONFIG.PLAYER_ID ? GAME_CONFIG.OPPONENT_ID : GAME_CONFIG.PLAYER_ID;
        const defenderState = this.gameState[defenderRole];
        const attackerData = dataUtils.getCharacterData(attackerState.characterKey);
        const defenderData = dataUtils.getCharacterData(defenderState.characterKey);

        if (!attackerData || !defenderData) { this._handleCriticalError('action_char_data_fail', 'Ошибка данных персонажа при действии.'); return; }

        let actionValid = true;
        let tauntContextTargetData = defenderData; // Данные цели для контекста насмешек

        if (actionData.actionType === 'attack') {
            const taunt = gameLogic.getRandomTaunt(attackerState.characterKey, 'basicAttack', {}, GAME_CONFIG, tauntContextTargetData, this.gameState);
            if (taunt !== "(Молчание)") this.addToLog(`${attackerState.name}: "${taunt}"`, GAME_CONFIG.LOG_TYPE_INFO);
            gameLogic.performAttack(attackerState, defenderState, attackerData.baseStats, defenderData.baseStats, this.gameState, this.addToLog.bind(this), GAME_CONFIG, tauntContextTargetData);
            const delayedBuff = attackerState.activeEffects.find(eff => eff.isDelayed && (eff.id === GAME_CONFIG.ABILITY_ID_NATURE_STRENGTH || eff.id === GAME_CONFIG.ABILITY_ID_ALMAGEST_BUFF_ATTACK));
            if (delayedBuff && !delayedBuff.justCast) {
                const regen = Math.min(GAME_CONFIG.NATURE_STRENGTH_MANA_REGEN, attackerData.baseStats.maxResource - attackerState.currentResource);
                if (regen > 0) {
                    attackerState.currentResource = Math.round(attackerState.currentResource + regen);
                    this.addToLog(`🌿 ${attackerState.name} восстанавливает ${regen} ${attackerState.resourceName} от "${delayedBuff.name}"!`, GAME_CONFIG.LOG_TYPE_HEAL);
                }
            }
        } else if (actionData.actionType === 'ability' && actionData.abilityId) {
            const ability = attackerData.abilities.find(ab => ab.id === actionData.abilityId);
            if (!ability) {
                actionValid = false;
                actingPlayerInfo.socket.emit('gameError', { message: "Неизвестная способность." });
                this.turnTimer.start(this.gameState.isPlayerTurn, (this.mode === 'ai' && !this.gameState.isPlayerTurn)); // Перезапуск таймера
                return;
            }
            const validityCheck = gameLogic.checkAbilityValidity(ability, attackerState, defenderState, GAME_CONFIG);
            if (!validityCheck.isValid) {
                this.addToLog(validityCheck.reason, GAME_CONFIG.LOG_TYPE_INFO);
                actionValid = false;
            }

            if (actionValid) {
                attackerState.currentResource = Math.round(attackerState.currentResource - ability.cost);
                const taunt = gameLogic.getRandomTaunt(attackerState.characterKey, 'selfCastAbility', { abilityId: ability.id }, GAME_CONFIG, tauntContextTargetData, this.gameState);
                if (taunt !== "(Молчание)") this.addToLog(`${attackerState.name}: "${taunt}"`, GAME_CONFIG.LOG_TYPE_INFO);
                gameLogic.applyAbilityEffect(ability, attackerState, defenderState, attackerData.baseStats, defenderData.baseStats, this.gameState, this.addToLog.bind(this), GAME_CONFIG, tauntContextTargetData);
                gameLogic.setAbilityCooldown(ability, attackerState, GAME_CONFIG);
            }
        } else {
            console.warn(`[GameInstance ${this.id}] Неизвестный тип действия: ${actionData?.actionType}`);
            actionValid = false;
        }

        if (this.checkGameOver()) {
            this.broadcastGameStateUpdate(); return;
        }
        if (actionValid) {
            setTimeout(() => this.switchTurn(), GAME_CONFIG.DELAY_AFTER_PLAYER_ACTION);
        } else {
            this.broadcastLogUpdate();
            this.turnTimer.start(this.gameState.isPlayerTurn, (this.mode === 'ai' && !this.gameState.isPlayerTurn)); // Перезапуск таймера
        }
    }

    switchTurn() {
        if (!this.gameState || this.gameState.isGameOver) return;
        this.turnTimer.clear();

        const endingTurnActorRole = this.gameState.isPlayerTurn ? GAME_CONFIG.PLAYER_ID : GAME_CONFIG.OPPONENT_ID;
        const endingTurnActor = this.gameState[endingTurnActorRole];
        const endingTurnData = dataUtils.getCharacterData(endingTurnActor.characterKey);

        if (!endingTurnData) { this._handleCriticalError('switch_turn_data_fail', 'Ошибка данных при смене хода.'); return; }

        gameLogic.processEffects(endingTurnActor.activeEffects, endingTurnActor, endingTurnData.baseStats, endingTurnActorRole, this.gameState, this.addToLog.bind(this), GAME_CONFIG, dataUtils);
        gameLogic.updateBlockingStatus(this.gameState.player);
        gameLogic.updateBlockingStatus(this.gameState.opponent);
        if (endingTurnActor.abilityCooldowns && endingTurnData.abilities) gameLogic.processPlayerAbilityCooldowns(endingTurnActor.abilityCooldowns, endingTurnData.abilities, endingTurnActor.name, this.addToLog.bind(this), GAME_CONFIG);
        if (endingTurnActor.characterKey === 'balard') gameLogic.processBalardSpecialCooldowns(endingTurnActor);
        if (endingTurnActor.disabledAbilities?.length > 0 && endingTurnData.abilities) gameLogic.processDisabledAbilities(endingTurnActor.disabledAbilities, endingTurnData.abilities, endingTurnActor.name, this.addToLog.bind(this), GAME_CONFIG);

        if (this.checkGameOver()) { this.broadcastGameStateUpdate(); return; }

        this.gameState.isPlayerTurn = !this.gameState.isPlayerTurn;
        if (this.gameState.isPlayerTurn) this.gameState.turnNumber++;

        const currentTurnActor = this.gameState.isPlayerTurn ? this.gameState.player : this.gameState.opponent;
        this.addToLog(`--- Начинается ход ${this.gameState.turnNumber} для: ${currentTurnActor.name} ---`, GAME_CONFIG.LOG_TYPE_TURN);
        this.broadcastGameStateUpdate();
        this.turnTimer.start(this.gameState.isPlayerTurn, (this.mode === 'ai' && !this.gameState.isPlayerTurn));

        if (!this.gameState.isPlayerTurn && this.aiOpponent) {
            setTimeout(() => this.processAiTurn(), GAME_CONFIG.DELAY_OPPONENT_TURN);
        }
    }

    processAiTurn() {
        if (!this.gameState || this.gameState.isGameOver || this.gameState.isPlayerTurn || !this.aiOpponent || this.gameState.opponent?.characterKey !== 'balard') {
            if (this.gameState && !this.gameState.isGameOver) this.switchTurn();
            return;
        }

        const attacker = this.gameState.opponent;
        const defender = this.gameState.player;
        const attackerData = dataUtils.getCharacterData('balard');
        const defenderData = dataUtils.getCharacterData(defender.characterKey);

        if (!attackerData || !defenderData) { this._handleCriticalError('ai_char_data_fail', 'Ошибка данных AI.'); this.switchTurn(); return; }

        if (gameLogic.isCharacterFullySilenced(attacker, GAME_CONFIG)) {
            this.addToLog(`😵 ${attacker.name} под действием Безмолвия! Атакует в смятении.`, GAME_CONFIG.LOG_TYPE_EFFECT);
            gameLogic.performAttack(attacker, defender, attackerData.baseStats, defenderData.baseStats, this.gameState, this.addToLog.bind(this), GAME_CONFIG, defenderData);
            if (this.checkGameOver()) { this.broadcastGameStateUpdate(); return; }
            setTimeout(() => this.switchTurn(), GAME_CONFIG.DELAY_AFTER_PLAYER_ACTION);
            return;
        }

        const aiDecision = gameLogic.decideAiAction(this.gameState, dataUtils, GAME_CONFIG, this.addToLog.bind(this));
        let tauntContextTargetData = defenderData;

        if (aiDecision.actionType === 'attack') {
            gameLogic.performAttack(attacker, defender, attackerData.baseStats, defenderData.baseStats, this.gameState, this.addToLog.bind(this), GAME_CONFIG, tauntContextTargetData);
        } else if (aiDecision.actionType === 'ability' && aiDecision.ability) {
            attacker.currentResource = Math.round(attacker.currentResource - aiDecision.ability.cost);
            gameLogic.applyAbilityEffect(aiDecision.ability, attacker, defender, attackerData.baseStats, defenderData.baseStats, this.gameState, this.addToLog.bind(this), GAME_CONFIG, tauntContextTargetData);
            gameLogic.setAbilityCooldown(aiDecision.ability, attacker, GAME_CONFIG);
        } // 'pass' уже залогирован в decideAiAction

        if (this.checkGameOver()) { this.broadcastGameStateUpdate(); return; }
        setTimeout(() => this.switchTurn(), GAME_CONFIG.DELAY_AFTER_PLAYER_ACTION);
    }

    checkGameOver() {
        if (!this.gameState || this.gameState.isGameOver) return this.gameState?.isGameOver ?? true;
        if (!this.gameState.player || !this.gameState.opponent?.characterKey) return false;

        const gameOverResult = gameLogic.getGameOverResult(this.gameState, GAME_CONFIG, this.mode);
        if (gameOverResult.isOver) {
            this.gameState.isGameOver = true;
            this.turnTimer.clear();
            this.addToLog(gameOverResult.logMessage, GAME_CONFIG.LOG_TYPE_SYSTEM);

            const winnerState = this.gameState[gameOverResult.winnerRole];
            const loserState = this.gameState[gameOverResult.loserRole];
            if (winnerState && (winnerState.characterKey === 'elena' || winnerState.characterKey === 'almagest') && loserState) {
                const loserFullData = dataUtils.getCharacterData(loserState.characterKey);
                if (loserFullData) { // Убедимся, что данные проигравшего есть
                    const taunt = gameLogic.getRandomTaunt(winnerState.characterKey, 'opponentNearDefeatCheck', {}, GAME_CONFIG, loserFullData, this.gameState);
                    if (taunt !== "(Молчание)") this.addToLog(`${winnerState.name}: "${taunt}"`, GAME_CONFIG.LOG_TYPE_INFO);
                }
            }
            if (loserState) {
                if (loserState.characterKey === 'balard') this.addToLog(`Елена исполнила свой тяжкий долг. ${loserState.name} развоплощен...`, GAME_CONFIG.LOG_TYPE_SYSTEM);
                else if (loserState.characterKey === 'almagest') this.addToLog(`Над полем битвы воцаряется тишина. ${loserState.name} побежден(а).`, GAME_CONFIG.LOG_TYPE_SYSTEM);
                else if (loserState.characterKey === 'elena') this.addToLog(`Свет погас. ${loserState.name} повержен(а).`, GAME_CONFIG.LOG_TYPE_SYSTEM);
            }

            console.log(`[GameInstance ${this.id}] Игра окончена. Победитель: ${gameOverResult.winnerRole || 'Нет'}. Причина: ${gameOverResult.reason}.`);
            this.io.to(this.id).emit('gameOver', {
                winnerId: gameOverResult.winnerRole, reason: gameOverResult.reason,
                finalGameState: this.gameState, log: this.consumeLogBuffer(),
                loserCharacterKey: loserState?.characterKey || 'unknown'
            });
            this.gameManager._cleanupGame(this.id, gameOverResult.reason);
            return true;
        }
        return false;
    }

    endGameDueToDisconnect(disconnectedSocketId, disconnectedPlayerRole, disconnectedCharacterKey) {
        if (this.gameState && !this.gameState.isGameOver) {
            this.gameState.isGameOver = true;
            this.turnTimer.clear();

            const result = gameLogic.getGameOverResult(this.gameState, GAME_CONFIG, this.mode, 'opponent_disconnected',
                disconnectedPlayerRole === GAME_CONFIG.PLAYER_ID ? GAME_CONFIG.OPPONENT_ID : GAME_CONFIG.PLAYER_ID, // winner
                disconnectedPlayerRole // loser
            );

            this.addToLog(result.logMessage, GAME_CONFIG.LOG_TYPE_SYSTEM);

            console.log(`[GameInstance ${this.id}] Игра завершена из-за дисконнекта. Победитель: ${result.winnerRole || 'Нет'}. Отключился: ${disconnectedPlayerRole}.`);
            this.io.to(this.id).emit('gameOver', {
                winnerId: result.winnerRole, reason: result.reason,
                finalGameState: this.gameState, log: this.consumeLogBuffer(),
                loserCharacterKey: disconnectedCharacterKey // Ключ того, кто отключился
            });
            this.gameManager._cleanupGame(this.id, result.reason);
        }
    }

    handleTurnTimeout() {
        if (!this.gameState || this.gameState.isGameOver) return;
        // this.turnTimer.clear(); // TurnTimer сам себя очистит при вызове onTimeout

        const timedOutPlayerRole = this.gameState.isPlayerTurn ? GAME_CONFIG.PLAYER_ID : GAME_CONFIG.OPPONENT_ID;
        const winnerPlayerRole = timedOutPlayerRole === GAME_CONFIG.PLAYER_ID ? GAME_CONFIG.OPPONENT_ID : GAME_CONFIG.PLAYER_ID;

        const result = gameLogic.getGameOverResult(this.gameState, GAME_CONFIG, this.mode, 'turn_timeout', winnerPlayerRole, timedOutPlayerRole);

        if (!this.gameState[winnerPlayerRole]?.characterKey) { // Если победитель не определен (например, ожидание в PvP)
            this._handleCriticalError('timeout_winner_undefined', `Таймаут, но победитель (${winnerPlayerRole}) не определен.`);
            return;
        }

        this.gameState.isGameOver = true; // Устанавливаем здесь, т.к. getGameOverResult мог не знать, что игра уже окончена
        this.addToLog(result.logMessage, GAME_CONFIG.LOG_TYPE_SYSTEM);
        console.log(`[GameInstance ${this.id}] Таймаут хода для ${this.gameState[timedOutPlayerRole]?.name}. Победитель: ${this.gameState[winnerPlayerRole]?.name}.`);

        this.io.to(this.id).emit('gameOver', {
            winnerId: result.winnerRole, reason: result.reason,
            finalGameState: this.gameState, log: this.consumeLogBuffer(),
            loserCharacterKey: this.gameState[timedOutPlayerRole]?.characterKey || 'unknown'
        });
        this.gameManager._cleanupGame(this.id, result.reason);
    }

    _handleCriticalError(reasonCode, logMessage) {
        console.error(`[GameInstance ${this.id}] КРИТИЧЕСКАЯ ОШИБКА: ${logMessage} (Код: ${reasonCode})`);
        if (this.gameState && !this.gameState.isGameOver) this.gameState.isGameOver = true;
        this.turnTimer.clear();
        this.addToLog(`Критическая ошибка сервера: ${logMessage}`, GAME_CONFIG.LOG_TYPE_SYSTEM);
        this.io.to(this.id).emit('gameOver', {
            winnerId: null, reason: `server_error_${reasonCode}`,
            finalGameState: this.gameState, log: this.consumeLogBuffer(),
            loserCharacterKey: 'unknown'
        });
        if (this.gameManager && typeof this.gameManager._cleanupGame === 'function') {
            this.gameManager._cleanupGame(this.id, `critical_error_${reasonCode}`);
        }
    }

    addToLog(message, type = GAME_CONFIG.LOG_TYPE_INFO) {
        if (!message) return;
        this.logBuffer.push({ message, type, timestamp: Date.now() });
    }
    consumeLogBuffer() {
        const logs = [...this.logBuffer]; this.logBuffer = []; return logs;
    }
    broadcastGameStateUpdate() {
        if (!this.gameState) return;
        this.io.to(this.id).emit('gameStateUpdate', { gameState: this.gameState, log: this.consumeLogBuffer() });
    }
    broadcastLogUpdate() {
        if (this.logBuffer.length > 0) {
            this.io.to(this.id).emit('logUpdate', { log: this.consumeLogBuffer() });
        }
    }
}

module.exports = GameInstance;