// /server/game/logic/combatLogic.js

// GAME_CONFIG и gameData/dataUtils будут передаваться в функции как параметры.
// const GAME_CONFIG_STATIC = require('../../core/config'); // Можно импортировать для внутренних нужд, если не все приходит через параметры

/**
 * Обрабатывает базовую атаку одного бойца по другому.
 * @param {object} attackerState - Состояние атакующего бойца из gameState.
 * @param {object} defenderState - Состояние защищающегося бойца из gameState.
 * @param {object} attackerBaseStats - Базовые статы атакующего (из dataUtils.getCharacterBaseStats).
 * @param {object} defenderBaseStats - Базовые статы защищающегося (из dataUtils.getCharacterBaseStats).
 * @param {object} currentGameState - Текущее полное состояние игры (для getRandomTaunt).
 * @param {function} addToLogCallback - Функция для добавления сообщений в лог игры.
 * @param {object} configToUse - Конфигурационный объект игры (GAME_CONFIG).
 * @param {object} defenderFullData - Полные данные защищающегося персонажа (baseStats, abilities) из dataUtils.getCharacterData(defenderKey), для getRandomTaunt.
 */
function performAttack(
    attackerState,
    defenderState,
    attackerBaseStats,
    defenderBaseStats,
    currentGameState, // Добавлен для контекста насмешек
    addToLogCallback,
    configToUse,
    defenderFullData // Добавлен для контекста насмешек цели
) {
    // Расчет базового урона с вариацией
    let damage = Math.floor(
        attackerBaseStats.attackPower *
        (configToUse.DAMAGE_VARIATION_MIN + Math.random() * configToUse.DAMAGE_VARIATION_RANGE)
    );
    let tauntMessagePart = "";

    // Проверка на блок
    if (defenderState.isBlocking) {
        const initialDamage = damage;
        damage = Math.floor(damage * configToUse.BLOCK_DAMAGE_REDUCTION);

        // Проверка на насмешку ОТ защищающегося (если это Елена или Альмагест) при блокировании атаки
        if (defenderState.characterKey === 'elena' || defenderState.characterKey === 'almagest') {
            // Импортируем getRandomTaunt здесь или передаем как параметр, если он в другом файле logic
            // Предположим, getRandomTaunt доступен в gameLogic (который будет передан или импортирован)
            // Для примера, если бы он был в этом же файле или импортирован:
            // const blockTaunt = getRandomTaunt(defenderState.characterKey, 'onOpponentAttackBlocked', {}, configToUse, gameData, currentGameState);
            // Поскольку getRandomTaunt теперь в gameLogic.js, он должен быть вызван оттуда или передан.
            // В GameInstance.js мы вызываем gameLogic.getRandomTaunt, так что здесь это дублирование.
            // Лучше, чтобы GameInstance сам обрабатывал насмешки или передавал их как результат.
            // Для простоты здесь оставим, но это кандидат на рефакторинг вызова насмешек в GameInstance.
            // Однако, если defenderFullData передается, мы можем вызвать его, предполагая, что gameLogic.getRandomTaunt будет импортирован
            // или доступен в объекте gameLogic, переданном в GameInstance.
            // const blockTaunt = require('./index').getRandomTaunt(...) // Пример циклической зависимости, так не надо
            // Будем считать, что GameInstance готовит насмешку заранее или эта функция вызывается с уже готовой насмешкой.
            // Либо, если getRandomTaunt - это часть 'gameLogic' объекта, то:
            // const blockTaunt = gameLogicFunctions.getRandomTaunt(...)
            // Сейчас для простоты оставим вызов, но это архитектурный момент.
            // Предположим, что gameLogic.getRandomTaunt доступен через какой-то объект, например, `sharedLogic`
        }


        if (addToLogCallback) {
            addToLogCallback(
                `🛡️ ${defenderBaseStats.name} блокирует атаку ${attackerBaseStats.name}! Урон снижен (${initialDamage} -> ${damage}).${tauntMessagePart}`,
                configToUse.LOG_TYPE_BLOCK
            );
        }
    } else {
        // Насмешка при попадании также должна обрабатываться централизованно или передаваться
        if (addToLogCallback) {
            addToLogCallback(
                `${attackerBaseStats.name} атакует ${defenderBaseStats.name}! Наносит ${damage} урона.${tauntMessagePart}`,
                configToUse.LOG_TYPE_DAMAGE
            );
        }
    }

    // Применяем урон, убеждаемся, что HP не ниже нуля
    defenderState.currentHp = Math.max(0, Math.round(defenderState.currentHp - damage));
}


/**
 * Применяет эффект способности (урон, лечение, наложение баффа/дебаффа и т.д.).
 * Насмешки, связанные с самим КАСТОМ способности (selfCastAbility), должны быть обработаны до вызова этой функции.
 * Насмешки, связанные с РЕАКЦИЕЙ цели на эффект, могут быть обработаны здесь или после.
 * @param {object} ability - Объект способности.
 * @param {object} casterState - Состояние бойца, применившего способность.
 * @param {object} targetState - Состояние цели способности.
 * @param {object} casterBaseStats - Базовые статы кастера.
 * @param {object} targetBaseStats - Базовые статы цели.
 * @param {object} currentGameState - Текущее полное состояние игры (для getRandomTaunt, если он здесь вызывается).
 * @param {function} addToLogCallback - Функция для добавления лога.
 * @param {object} configToUse - Конфигурация игры.
 * @param {object} targetFullData - Полные данные цели (baseStats, abilities) для getRandomTaunt.
 */
function applyAbilityEffect(
    ability,
    casterState,
    targetState,
    casterBaseStats,
    targetBaseStats,
    currentGameState,
    addToLogCallback,
    configToUse,
    targetFullData // Для насмешек цели
) {
    let tauntMessagePart = ""; // Для насмешки цели

    // Насмешка цели (если это Елена/Альмагест) на применение способности противником
    // Этот вызов лучше делать в GameInstance, передавая результат сюда, или эта функция должна иметь доступ к getRandomTaunt
    // if ((targetState.characterKey === 'elena' || targetState.characterKey === 'almagest') && casterState.id !== targetState.id) {
    //     const reactionTaunt = require('./index').getRandomTaunt(targetState.characterKey, 'onOpponentAction', { abilityId: ability.id }, configToUse, targetFullData, currentGameState);
    //     if (reactionTaunt !== "(Молчание)") tauntMessagePart = ` (${reactionTaunt})`;
    // }

    switch (ability.type) {
        case configToUse.ACTION_TYPE_HEAL:
            const healAmount = Math.floor(ability.power * (configToUse.HEAL_VARIATION_MIN + Math.random() * configToUse.HEAL_VARIATION_RANGE));
            const actualHeal = Math.min(healAmount, casterBaseStats.maxHp - casterState.currentHp);
            if (actualHeal > 0) {
                casterState.currentHp = Math.round(casterState.currentHp + actualHeal);
                if (addToLogCallback) addToLogCallback(`💚 ${casterBaseStats.name} применяет "${ability.name}" и восстанавливает ${actualHeal} HP!${tauntMessagePart}`, configToUse.LOG_TYPE_HEAL);
            } else {
                if (addToLogCallback) addToLogCallback(`✨ ${casterBaseStats.name} применяет "${ability.name}", но не получает лечения.${tauntMessagePart}`, configToUse.LOG_TYPE_INFO);
            }
            break;

        case configToUse.ACTION_TYPE_DAMAGE:
            let damage = Math.floor(ability.power * (configToUse.DAMAGE_VARIATION_MIN + Math.random() * configToUse.DAMAGE_VARIATION_RANGE));
            if (targetState.isBlocking) {
                const initialDamage = damage;
                damage = Math.floor(damage * configToUse.BLOCK_DAMAGE_REDUCTION);
                if (addToLogCallback) addToLogCallback(`🛡️ ${targetBaseStats.name} блокирует "${ability.name}" от ${casterBaseStats.name}! Урон снижен (${initialDamage} -> ${damage}).${tauntMessagePart}`, configToUse.LOG_TYPE_BLOCK);
            }
            targetState.currentHp = Math.max(0, Math.round(targetState.currentHp - damage));
            if (addToLogCallback && !targetState.isBlocking) {
                addToLogCallback(`💥 ${casterBaseStats.name} применяет "${ability.name}" на ${targetBaseStats.name}, нанося ${damage} урона!${tauntMessagePart}`, configToUse.LOG_TYPE_DAMAGE);
            }
            break;

        case configToUse.ACTION_TYPE_BUFF:
            // Проверка на уже активный бафф должна быть сделана до вызова этой функции (в GameInstance)
            let effectDescriptionBuff = ability.description;
            if (typeof ability.descriptionFunction === 'function') {
                // Для описания баффа может потребоваться информация о противнике (цели баффа, если бафф накладывается на другого)
                // В данном случае, баффы накладываются на себя, так что targetBaseStats не всегда релевантен для описания.
                // Передаем targetBaseStats (оппонента кастера), если описание функции его ожидает.
                effectDescriptionBuff = ability.descriptionFunction(configToUse, targetBaseStats);
            }
            casterState.activeEffects.push({
                id: ability.id, name: ability.name, description: effectDescriptionBuff,
                type: ability.type, duration: ability.duration,
                turnsLeft: ability.duration, // Длительность эффекта в ходах владельца
                grantsBlock: !!ability.grantsBlock,
                isDelayed: !!ability.isDelayed,
                justCast: true
            });
            if (ability.grantsBlock) require('./effectsLogic').updateBlockingStatus(casterState); // Обновляем статус блока
            if (addToLogCallback) addToLogCallback(`✨ ${casterBaseStats.name} накладывает эффект "${ability.name}"!${tauntMessagePart}`, configToUse.LOG_TYPE_EFFECT);
            break;

        case configToUse.ACTION_TYPE_DISABLE:
            // Логика для 'Гипнотический взгляд' / 'Раскол Разума' (полное безмолвие)
            if (ability.id === configToUse.ABILITY_ID_HYPNOTIC_GAZE || ability.id === configToUse.ABILITY_ID_ALMAGEST_DISABLE) {
                const effectIdFullSilence = ability.id === configToUse.ABILITY_ID_HYPNOTIC_GAZE ? 'fullSilenceByElena' : 'fullSilenceByAlmagest';
                if (!targetState.activeEffects.some(e => e.id === effectIdFullSilence)) {
                    targetState.activeEffects.push({
                        id: effectIdFullSilence, name: ability.name, description: ability.description,
                        type: ability.type, duration: ability.effectDuration, turnsLeft: ability.effectDuration,
                        power: ability.power, isFullSilence: true, justCast: true
                    });
                    if (addToLogCallback) addToLogCallback(`🌀 ${casterBaseStats.name} применяет "${ability.name}" на ${targetBaseStats.name}! Способности заблокированы на ${ability.effectDuration} хода и наносится урон!${tauntMessagePart}`, configToUse.LOG_TYPE_EFFECT);
                } else {
                    if (addToLogCallback) addToLogCallback(`${casterBaseStats.name} пытается применить "${ability.name}", но эффект уже активен на ${targetState.name}!${tauntMessagePart}`, configToUse.LOG_TYPE_INFO);
                }
            }
            // Логика для 'Эхо Безмолвия' Баларда
            else if (ability.id === configToUse.ABILITY_ID_BALARD_SILENCE && casterState.characterKey === 'balard') {
                const success = Math.random() < configToUse.SILENCE_SUCCESS_RATE;
                // Насмешка цели на успех/провал должна быть обработана в GameInstance, т.к. результат известен только здесь
                if (success) {
                    const targetAbilitiesList = require('../../data/dataUtils').getCharacterAbilities(targetState.characterKey); // Получаем абилки цели
                    const availableAbilitiesToSilence = targetAbilitiesList.filter(pa =>
                        !targetState.disabledAbilities?.some(d => d.abilityId === pa.id) &&
                        !targetState.activeEffects?.some(eff => eff.id === `playerSilencedOn_${pa.id}`)
                    );
                    if (availableAbilitiesToSilence.length > 0) {
                        const abilityToSilence = availableAbilitiesToSilence[Math.floor(Math.random() * availableAbilitiesToSilence.length)];
                        const turns = configToUse.SILENCE_DURATION;
                        targetState.disabledAbilities.push({ abilityId: abilityToSilence.id, turnsLeft: turns + 1 });
                        targetState.activeEffects.push({
                            id: `playerSilencedOn_${abilityToSilence.id}`, name: `Безмолвие: ${abilityToSilence.name}`,
                            description: `Способность "${abilityToSilence.name}" временно недоступна.`,
                            type: configToUse.ACTION_TYPE_DISABLE, sourceAbilityId: ability.id,
                            duration: turns, turnsLeft: turns + 1, justCast: true
                        });
                        if (addToLogCallback) addToLogCallback(`🔇 Эхо Безмолвия! "${abilityToSilence.name}" у ${targetBaseStats.name} заблокировано на ${turns} хода!${tauntMessagePart}`, configToUse.LOG_TYPE_EFFECT);
                    } else {
                        if (addToLogCallback) addToLogCallback(`${casterBaseStats.name} пытается наложить Безмолвие, но у ${targetBaseStats.name} нечего глушить!${tauntMessagePart}`, configToUse.LOG_TYPE_INFO);
                    }
                } else {
                    if (addToLogCallback) addToLogCallback(`💨 Попытка ${casterBaseStats.name} наложить Безмолвие на ${targetBaseStats.name} провалилась!${tauntMessagePart}`, configToUse.LOG_TYPE_INFO);
                }
            }
            break;

        case configToUse.ACTION_TYPE_DEBUFF:
            // Логика для 'Печать Слабости' / 'Проклятие Увядания'
            if (ability.id === configToUse.ABILITY_ID_SEAL_OF_WEAKNESS || ability.id === configToUse.ABILITY_ID_ALMAGEST_DEBUFF) {
                const effectIdDebuff = 'effect_' + ability.id;
                if (!targetState.activeEffects.some(e => e.id === effectIdDebuff)) {
                    let effectDescriptionDebuff = ability.description;
                    if (typeof ability.descriptionFunction === 'function') {
                        effectDescriptionDebuff = ability.descriptionFunction(configToUse, targetBaseStats);
                    }
                    targetState.activeEffects.push({
                        id: effectIdDebuff, name: ability.name, description: effectDescriptionDebuff,
                        type: configToUse.ACTION_TYPE_DEBUFF, sourceAbilityId: ability.id,
                        duration: ability.effectDuration, turnsLeft: ability.effectDuration,
                        power: ability.power, justCast: true
                    });
                    if (addToLogCallback) addToLogCallback(`📉 ${casterBaseStats.name} накладывает "${ability.name}" на ${targetBaseStats.name}! Ресурс будет сжигаться.${tauntMessagePart}`, configToUse.LOG_TYPE_EFFECT);
                } else {
                    if (addToLogCallback) addToLogCallback(`${casterBaseStats.name} пытается применить "${ability.name}", но эффект уже активен на ${targetState.name}!${tauntMessagePart}`, configToUse.LOG_TYPE_INFO);
                }
            }
            break;

        case configToUse.ACTION_TYPE_DRAIN: // Похищение Света Баларда
            if (casterState.characterKey === 'balard') {
                let manaDrained = 0; let healthGained = 0; let damageDealtDrain = 0;
                if (ability.powerDamage > 0) {
                    let baseDamageDrain = ability.powerDamage;
                    if (targetState.isBlocking) baseDamageDrain = Math.floor(baseDamageDrain * configToUse.BLOCK_DAMAGE_REDUCTION);
                    damageDealtDrain = Math.max(0, baseDamageDrain);
                    targetState.currentHp = Math.max(0, Math.round(targetState.currentHp - damageDealtDrain));
                }
                const potentialDrain = ability.powerManaDrain;
                const actualDrain = Math.min(potentialDrain, targetState.currentResource);
                if (actualDrain > 0) {
                    targetState.currentResource = Math.max(0, Math.round(targetState.currentResource - actualDrain));
                    manaDrained = actualDrain;
                    const potentialHeal = Math.floor(manaDrained * ability.powerHealthGainFactor);
                    const actualHealGain = Math.min(potentialHeal, casterBaseStats.maxHp - casterState.currentHp);
                    casterState.currentHp = Math.round(casterState.currentHp + actualHealGain);
                    healthGained = actualHealGain;
                }
                let logMsgDrain = `⚡ ${casterBaseStats.name} применяет "${ability.name}"! `;
                if (damageDealtDrain > 0) logMsgDrain += `Наносит ${damageDealtDrain} урона. `;
                if (manaDrained > 0) logMsgDrain += `Вытягивает ${manaDrained} ${targetBaseStats.resourceName} у ${targetBaseStats.name} и исцеляется на ${healthGained} HP!`;
                else if (damageDealtDrain > 0) logMsgDrain += `У ${targetBaseStats.name} нет ${targetBaseStats.resourceName} для похищения.`;
                else logMsgDrain += `У ${targetBaseStats.name} нет ${targetBaseStats.resourceName} для похищения.`;
                logMsgDrain += tauntMessagePart;
                if (addToLogCallback) addToLogCallback(logMsgDrain, (manaDrained > 0 || damageDealtDrain > 0) ? configToUse.LOG_TYPE_DAMAGE : configToUse.LOG_TYPE_INFO);
            }
            break;

        default:
            if (addToLogCallback) addToLogCallback(`Неизвестный тип способности: ${ability?.type} для "${ability?.name}"`, configToUse.LOG_TYPE_SYSTEM);
            console.warn(`applyAbilityEffect: Неизвестный тип способности: ${ability?.type}`);
    }
}

/**
 * Проверяет валидность использования способности (ресурс, КД, безмолвие и т.д.).
 * @param {object} ability - Объект способности.
 * @param {object} casterState - Состояние кастера.
 * @param {object} targetState - Состояние цели.
 * @param {object} configToUse - Конфигурация игры.
 * @returns {{isValid: boolean, reason: string|null}} Результат проверки.
 */
function checkAbilityValidity(ability, casterState, targetState, configToUse) {
    if (!ability) return { isValid: false, reason: "Способность не найдена." };

    if (casterState.currentResource < ability.cost) {
        return { isValid: false, reason: `${casterState.name} пытается применить "${ability.name}", но не хватает ${casterState.resourceName}!` };
    }
    if ((casterState.abilityCooldowns?.[ability.id] || 0) > 0) {
        return { isValid: false, reason: `"${ability.name}" еще на перезарядке.` };
    }
    // Проверка специальных КД Баларда
    if (casterState.characterKey === 'balard') {
        if (ability.id === configToUse.ABILITY_ID_BALARD_SILENCE && (casterState.silenceCooldownTurns || 0) > 0) {
            return { isValid: false, reason: `"${ability.name}" (спец. КД) еще на перезарядке.` };
        }
        if (ability.id === configToUse.ABILITY_ID_BALARD_MANA_DRAIN && (casterState.manaDrainCooldownTurns || 0) > 0) {
            return { isValid: false, reason: `"${ability.name}" (спец. КД) еще на перезарядке.` };
        }
    }

    const isCasterFullySilenced = casterState.activeEffects.some(eff => eff.isFullSilence && eff.turnsLeft > 0);
    const isAbilitySpecificallySilenced = casterState.disabledAbilities?.some(dis => dis.abilityId === ability.id && dis.turnsLeft > 0);
    if (isCasterFullySilenced || isAbilitySpecificallySilenced) {
        return { isValid: false, reason: `${casterState.name} не может использовать способности из-за безмолвия!` };
    }

    if (ability.type === configToUse.ACTION_TYPE_BUFF && casterState.activeEffects.some(e => e.id === ability.id)) {
        return { isValid: false, reason: `Эффект "${ability.name}" уже активен!` };
    }

    const isTargetedDebuff = ability.id === configToUse.ABILITY_ID_SEAL_OF_WEAKNESS || ability.id === configToUse.ABILITY_ID_ALMAGEST_DEBUFF;
    if (isTargetedDebuff && targetState.activeEffects.some(e => e.id === 'effect_' + ability.id)) {
        return { isValid: false, reason: `Эффект "${ability.name}" уже наложен на ${targetState.name}!` };
    }

    return { isValid: true, reason: null };
}


module.exports = {
    performAttack,
    applyAbilityEffect,
    checkAbilityValidity // Экспортируем новую функцию
};