"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.handleDeathrattles = exports.processDeathrattleForMinion = exports.orchestrateMinionDeathEffects = void 0;
const reference_data_1 = require("@firestone-hs/reference-data");
const utils_1 = require("../utils");
const avenge_1 = require("./avenge");
const death_effects_1 = require("./death-effects");
const deathrattle_effects_1 = require("./deathrattle-effects");
const deathrattle_spawns_1 = require("./deathrattle-spawns");
const reborn_1 = require("./reborn");
const spawns_1 = require("./spawns");
const orchestrateMinionDeathEffects = (deathrattleInput, processAvenge = true, processReborn = true) => {
    handleAfterMinionsKillEffects(deathrattleInput);
    handleWheneverMinionsDieEffects(deathrattleInput);
    const playerBoardBefore = [...deathrattleInput.gameState.gameState.player.board];
    const opponentBoardBefore = [...deathrattleInput.gameState.gameState.opponent.board];
    const entitiesFromDeathrattles = processDeathrattles(deathrattleInput, processAvenge);
    handleAfterMinionsDieEffects(deathrattleInput);
    const playerBoardAfter = [...deathrattleInput.gameState.gameState.player.board];
    const opponentBoardAfter = [...deathrattleInput.gameState.gameState.opponent.board];
    const opponentIndexOfSpawnedEntities = opponentBoardAfter
        .filter((entity) => !opponentBoardBefore.includes(entity))
        .map((entity) => opponentBoardAfter.length - opponentBoardAfter.indexOf(entity) - 1);
    const playerIndexOfSpawnedEntities = playerBoardAfter
        .filter((entity) => !playerBoardBefore.includes(entity))
        .map((entity) => playerBoardAfter.length - playerBoardAfter.indexOf(entity) - 1);
    deathrattleInput.opponentDeadEntityIndexesFromRight = deathrattleInput.opponentDeadEntityIndexesFromRight.map((previousIndex) => {
        opponentIndexOfSpawnedEntities.forEach((index) => {
            if (index < previousIndex) {
                previousIndex++;
            }
        });
        return previousIndex;
    });
    deathrattleInput.playerDeadEntityIndexesFromRight = deathrattleInput.playerDeadEntityIndexesFromRight.map((previousIndex) => {
        playerIndexOfSpawnedEntities.forEach((index) => {
            if (index < previousIndex) {
                previousIndex++;
            }
        });
        return previousIndex;
    });
    if (processReborn) {
        processReborns(deathrattleInput);
    }
    const entitiesFromFeathermanes = processFeathermaneEffects(deathrattleInput);
    handlePostDeathrattleEffects(deathrattleInput, [...entitiesFromDeathrattles, ...entitiesFromFeathermanes]);
};
exports.orchestrateMinionDeathEffects = orchestrateMinionDeathEffects;
const handleAfterMinionsKillEffects = (deathrattleInput) => {
    const processPlayerFirst = Math.random() > 0.5;
    const playerStates = processPlayerFirst
        ? [deathrattleInput.gameState.gameState.player, deathrattleInput.gameState.gameState.opponent]
        : [deathrattleInput.gameState.gameState.opponent, deathrattleInput.gameState.gameState.player];
    const playerDeadEntities = processPlayerFirst
        ? [deathrattleInput.playerDeadEntities, deathrattleInput.opponentDeadEntities]
        : [deathrattleInput.opponentDeadEntities, deathrattleInput.playerDeadEntities];
    const playerDeadEntityIndexesFromRight = processPlayerFirst
        ? [deathrattleInput.playerDeadEntityIndexesFromRight, deathrattleInput.opponentDeadEntityIndexesFromRight]
        : [deathrattleInput.opponentDeadEntityIndexesFromRight, deathrattleInput.playerDeadEntityIndexesFromRight];
    for (let i = 0; i < 2; i++) {
        const deadEntities = playerDeadEntities[i];
        if (deadEntities.length >= 0) {
            for (let j = 0; j < deadEntities.length; j++) {
                const deadEntity = deadEntities[j];
                (0, deathrattle_effects_1.handleAfterMinionKillsEffect)(deadEntity, playerDeadEntityIndexesFromRight[i][j], playerStates[i].board, playerStates[i].player, playerStates[1 - i].board, playerStates[1 - i].player, deathrattleInput.gameState);
            }
        }
    }
};
const handleWheneverMinionsDieEffects = (deathrattleInput) => {
    const processPlayerFirst = Math.random() > 0.5;
    const playerStates = processPlayerFirst
        ? [deathrattleInput.gameState.gameState.player, deathrattleInput.gameState.gameState.opponent]
        : [deathrattleInput.gameState.gameState.opponent, deathrattleInput.gameState.gameState.player];
    const playerDeadEntities = processPlayerFirst
        ? [deathrattleInput.playerDeadEntities, deathrattleInput.opponentDeadEntities]
        : [deathrattleInput.opponentDeadEntities, deathrattleInput.playerDeadEntities];
    const playerDeadEntityIndexesFromRight = processPlayerFirst
        ? [deathrattleInput.playerDeadEntityIndexesFromRight, deathrattleInput.opponentDeadEntityIndexesFromRight]
        : [deathrattleInput.opponentDeadEntityIndexesFromRight, deathrattleInput.playerDeadEntityIndexesFromRight];
    for (let i = 0; i < 2; i++) {
        const deadEntities = playerDeadEntities[i];
        if (deadEntities.length >= 0) {
            for (let j = 0; j < deadEntities.length; j++) {
                const deadEntity = deadEntities[j];
                (0, deathrattle_effects_1.applyWheneverMinionDiesEffect)(deadEntity, playerDeadEntityIndexesFromRight[i][j], playerStates[i].board, playerStates[i].player, playerStates[1 - i].board, playerStates[1 - i].player, deathrattleInput.gameState);
            }
        }
    }
};
const handleAfterMinionsDieEffects = (deathrattleInput) => {
    const processPlayerFirst = Math.random() > 0.5;
    const playerStates = processPlayerFirst
        ? [deathrattleInput.gameState.gameState.player, deathrattleInput.gameState.gameState.opponent]
        : [deathrattleInput.gameState.gameState.opponent, deathrattleInput.gameState.gameState.player];
    const playerDeadEntities = processPlayerFirst
        ? [deathrattleInput.playerDeadEntities, deathrattleInput.opponentDeadEntities]
        : [deathrattleInput.opponentDeadEntities, deathrattleInput.playerDeadEntities];
    const playerDeadEntityIndexesFromRight = processPlayerFirst
        ? [deathrattleInput.playerDeadEntityIndexesFromRight, deathrattleInput.opponentDeadEntityIndexesFromRight]
        : [deathrattleInput.opponentDeadEntityIndexesFromRight, deathrattleInput.playerDeadEntityIndexesFromRight];
    for (let i = 0; i < 2; i++) {
        const deadEntities = playerDeadEntities[i];
        if (deadEntities.length >= 0) {
            for (let j = 0; j < deadEntities.length; j++) {
                const deadEntity = deadEntities[j];
                (0, deathrattle_effects_1.applyAfterMinionDiesEffect)(deadEntity, playerDeadEntityIndexesFromRight[i][j], playerStates[i].board, playerStates[i].player, playerStates[1 - i].board, playerStates[1 - i].player, deathrattleInput.gameState);
            }
        }
    }
};
const processDeathrattles = (deathrattleInput, processAvenge = true) => {
    const entitiesFromDeathrattles = [];
    const processPlayerFirst = Math.random() > 0.5;
    const playerStates = processPlayerFirst
        ? [deathrattleInput.gameState.gameState.player, deathrattleInput.gameState.gameState.opponent]
        : [deathrattleInput.gameState.gameState.opponent, deathrattleInput.gameState.gameState.player];
    const playerDeadEntities = processPlayerFirst
        ? [deathrattleInput.playerDeadEntities, deathrattleInput.opponentDeadEntities]
        : [deathrattleInput.opponentDeadEntities, deathrattleInput.playerDeadEntities];
    const playerDeadEntityIndexesFromRight = processPlayerFirst
        ? [deathrattleInput.playerDeadEntityIndexesFromRight, deathrattleInput.opponentDeadEntityIndexesFromRight]
        : [deathrattleInput.opponentDeadEntityIndexesFromRight, deathrattleInput.playerDeadEntityIndexesFromRight];
    for (let i = 0; i < 2; i++) {
        const deadEntities = playerDeadEntities[i];
        if (deadEntities.length >= 0) {
            const spawns = processDeathrattleForMinions(deadEntities, playerDeadEntityIndexesFromRight[i], playerStates[i], playerStates[1 - i], deathrattleInput, processAvenge);
            entitiesFromDeathrattles.push(...spawns);
        }
    }
    return entitiesFromDeathrattles;
};
const processFeathermaneEffects = (deathrattleInput, processAvenge = true) => {
    const entitiesFromDeathrattles = [];
    const processPlayerFirst = Math.random() > 0.5;
    const playerStates = processPlayerFirst
        ? [deathrattleInput.gameState.gameState.player, deathrattleInput.gameState.gameState.opponent]
        : [deathrattleInput.gameState.gameState.opponent, deathrattleInput.gameState.gameState.player];
    const playerDeadEntities = processPlayerFirst
        ? [deathrattleInput.playerDeadEntities, deathrattleInput.opponentDeadEntities]
        : [deathrattleInput.opponentDeadEntities, deathrattleInput.playerDeadEntities];
    const playerDeadEntityIndexesFromRight = processPlayerFirst
        ? [deathrattleInput.playerDeadEntityIndexesFromRight, deathrattleInput.opponentDeadEntityIndexesFromRight]
        : [deathrattleInput.opponentDeadEntityIndexesFromRight, deathrattleInput.playerDeadEntityIndexesFromRight];
    for (let i = 0; i < 2; i++) {
        const deadEntities = playerDeadEntities[i];
        if (deadEntities.length >= 0) {
            for (let j = 0; j < deadEntities.length; j++) {
                const deadEntity = deadEntities[j];
                const indexFromRight = playerDeadEntityIndexesFromRight[i][j];
                const modifiedIndexFromRight = Math.min(playerStates[i].board.length, indexFromRight);
                const deadEntityPlayerState = playerStates[i];
                const otherPlayerState = playerStates[1 - i];
                const spawns = processFeathermaneForMinion(deadEntity, indexFromRight, deadEntities, deadEntityPlayerState, otherPlayerState, deathrattleInput.gameState, processAvenge);
                entitiesFromDeathrattles.push(...spawns);
            }
        }
    }
    return entitiesFromDeathrattles;
};
const processFeathermaneForMinion = (deadEntity, indexFromRight, deadEntities, deadEntityPlayerState, otherPlayerState, gameState, processAvenge = true) => {
    var _a, _b;
    const maxSpawns = 7 - deadEntityPlayerState.board.length;
    const allSpawns = [];
    if ((0, utils_1.hasCorrectTribe)(deadEntity, deadEntityPlayerState.player, reference_data_1.Race.BEAST, gameState.anomalies, gameState.allCards)) {
        const feathermanes = (_b = (_a = deadEntityPlayerState.player.hand) === null || _a === void 0 ? void 0 : _a.filter((e) => !e.locked).filter((e) => e.cardId === "BG27_014" ||
            e.cardId === "BG27_014_G")) !== null && _b !== void 0 ? _b : [];
        for (const feathermaneSpawn of feathermanes) {
            if (allSpawns.length >= maxSpawns) {
                break;
            }
            feathermaneSpawn.locked = true;
            const spawns = (0, deathrattle_spawns_1.spawnEntities)(feathermaneSpawn.cardId, 1, deadEntityPlayerState.board, deadEntityPlayerState.player, otherPlayerState.board, otherPlayerState.player, gameState, deadEntity.friendly, false, false, true, { ...feathermaneSpawn });
            for (const spawn of spawns) {
                spawn.onCanceledSummon = () => (feathermaneSpawn.locked = false);
            }
            allSpawns.push(...spawns);
        }
    }
    (0, spawns_1.performEntitySpawns)(allSpawns, deadEntityPlayerState.board, deadEntityPlayerState.player, deadEntity, indexFromRight, otherPlayerState.board, otherPlayerState.player, gameState);
    return allSpawns;
};
const processDeathrattleForMinions = (deadEntities, playerDeadEntityIndexesFromRight, deadEntityPlayerState, otherPlayerState, input, processAvenge = true) => {
    const entitiesFromDeathrattles = [];
    for (let j = 0; j < deadEntities.length; j++) {
        const deadEntity = deadEntities[j];
        const indexFromRight = playerDeadEntityIndexesFromRight[j];
        const drEntities = handleNaturalDeathrattle(deadEntity, indexFromRight, deadEntities, deadEntityPlayerState, otherPlayerState, input.gameState);
        entitiesFromDeathrattles.push(...drEntities);
    }
    let avengeEntities = [];
    if (processAvenge) {
        for (let j = 0; j < deadEntities.length; j++) {
            const deadEntity = deadEntities[j];
            const indexFromRight = playerDeadEntityIndexesFromRight[j];
            avengeEntities = (0, avenge_1.applyAvengeEffects)(deadEntity, indexFromRight, deadEntityPlayerState.board, deadEntityPlayerState.player, otherPlayerState.board, otherPlayerState.player, input.gameState, entitiesFromDeathrattles);
        }
    }
    const allAfterDeathEntities = [];
    for (let j = 0; j < deadEntities.length; j++) {
        const deadEntity = deadEntities[j];
        const indexFromRight = playerDeadEntityIndexesFromRight[j];
        const afterDeathEntities = (0, death_effects_1.applyAfterDeathEffects)(deadEntity, indexFromRight, deadEntityPlayerState.board, deadEntityPlayerState.player, otherPlayerState.board, otherPlayerState.player, input.gameState);
        allAfterDeathEntities.push(...afterDeathEntities);
    }
    return [...entitiesFromDeathrattles, ...avengeEntities, ...allAfterDeathEntities];
};
const processDeathrattleForMinion = (deadEntity, indexFromRight, deadEntities, deadEntityPlayerState, otherPlayerState, gameState, processAvenge = true) => {
    const drEntities = handleNaturalDeathrattle(deadEntity, indexFromRight, deadEntities, deadEntityPlayerState, otherPlayerState, gameState);
    let avengeEntities = [];
    let afterDeathEntities = [];
    if (processAvenge) {
        avengeEntities = (0, avenge_1.applyAvengeEffects)(deadEntity, indexFromRight, deadEntityPlayerState.board, deadEntityPlayerState.player, otherPlayerState.board, otherPlayerState.player, gameState, [...drEntities]);
        afterDeathEntities = (0, death_effects_1.applyAfterDeathEffects)(deadEntity, indexFromRight, deadEntityPlayerState.board, deadEntityPlayerState.player, otherPlayerState.board, otherPlayerState.player, gameState);
    }
    return [...drEntities, ...avengeEntities, ...afterDeathEntities];
};
exports.processDeathrattleForMinion = processDeathrattleForMinion;
const handleNaturalDeathrattle = (deadEntity, indexFromRight, deadEntities, deadEntityPlayerState, otherPlayerState, gameState) => {
    var _a, _b;
    const modifiedIndexFromRight = Math.min(deadEntityPlayerState.board.length, indexFromRight);
    for (const dr of (_a = deadEntity.rememberedDeathrattles) !== null && _a !== void 0 ? _a : []) {
        const entityToProcess = {
            ...deadEntity,
            originalCardId: deadEntity.cardId,
            rememberedDeathrattles: undefined,
            deathrattleRepeats: (_b = dr.repeats) !== null && _b !== void 0 ? _b : 1,
            scriptDataNum1: dr.scriptDataNum1,
            scriptDataNum2: dr.scriptDataNum2,
            cardId: dr.cardId,
            pendingAttackBuffs: [],
            enchantments: deadEntity.enchantments.filter((e) => { var _a; return (_a = e.cardId) === null || _a === void 0 ? void 0 : _a.startsWith("BG20_GEM"); }),
            memory: dr.memory == null
                ? null
                : Array.isArray(dr.memory)
                    ? dr.memory.map((mem) => ({ ...mem }))
                    : { ...dr.memory },
        };
        const spawns = handleNaturalDeathrattle(entityToProcess, indexFromRight, deadEntities, deadEntityPlayerState, otherPlayerState, gameState);
    }
    const entitiesFromNativeDeathrattle = (0, deathrattle_spawns_1.spawnEntitiesFromDeathrattle)(deadEntity, modifiedIndexFromRight, deadEntityPlayerState.board, deadEntityPlayerState.player, otherPlayerState.board, otherPlayerState.player, deadEntities, gameState);
    return entitiesFromNativeDeathrattle;
};
const processReborns = (deathrattleInput) => {
    const processPlayerFirst = Math.random() > 0.5;
    const playerStates = processPlayerFirst
        ? [deathrattleInput.gameState.gameState.player, deathrattleInput.gameState.gameState.opponent]
        : [deathrattleInput.gameState.gameState.opponent, deathrattleInput.gameState.gameState.player];
    const playerDeadEntities = processPlayerFirst
        ? [deathrattleInput.playerDeadEntities, deathrattleInput.opponentDeadEntities]
        : [deathrattleInput.opponentDeadEntities, deathrattleInput.playerDeadEntities];
    const playerDeadEntityIndexesFromRight = processPlayerFirst
        ? [deathrattleInput.playerDeadEntityIndexesFromRight, deathrattleInput.opponentDeadEntityIndexesFromRight]
        : [deathrattleInput.opponentDeadEntityIndexesFromRight, deathrattleInput.playerDeadEntityIndexesFromRight];
    for (let i = 0; i < 2; i++) {
        const deadEntities = playerDeadEntities[i];
        if (deadEntities.length >= 0) {
            for (let j = 0; j < deadEntities.length; j++) {
                const deadEntity = deadEntities[j];
                const indexFromRight = playerDeadEntityIndexesFromRight[i][j];
                const modifiedIndexFromRight = Math.min(playerStates[i].board.length, indexFromRight);
                const deadEntityPlayerState = playerStates[i];
                const otherPlayerState = playerStates[1 - i];
                (0, reborn_1.handleRebornForEntity)(deadEntityPlayerState.board, deadEntityPlayerState.player, deadEntity, indexFromRight, otherPlayerState.board, otherPlayerState.player, deathrattleInput.gameState);
            }
        }
    }
};
const handlePostDeathrattleEffects = (deathrattleInput, entitiesFromDeathrattles) => {
    const processPlayerFirst = Math.random() > 0.5;
    const playerStates = processPlayerFirst
        ? [deathrattleInput.gameState.gameState.player, deathrattleInput.gameState.gameState.opponent]
        : [deathrattleInput.gameState.gameState.opponent, deathrattleInput.gameState.gameState.player];
    const playerDeadEntities = processPlayerFirst
        ? [deathrattleInput.playerDeadEntities, deathrattleInput.opponentDeadEntities]
        : [deathrattleInput.opponentDeadEntities, deathrattleInput.playerDeadEntities];
    const playerDeadEntityIndexesFromRight = processPlayerFirst
        ? [deathrattleInput.playerDeadEntityIndexesFromRight, deathrattleInput.opponentDeadEntityIndexesFromRight]
        : [deathrattleInput.opponentDeadEntityIndexesFromRight, deathrattleInput.playerDeadEntityIndexesFromRight];
    for (let i = 0; i < 2; i++) {
        const deadEntities = playerDeadEntities[i];
        const deadEntityPlayerState = playerStates[i];
        const otherPlayerState = playerStates[1 - i];
        if (deadEntities.length >= 0) {
            for (let j = deadEntities.length - 1; j >= 0; j--) {
                const deadEntity = deadEntities[j];
                const indexFromRight = playerDeadEntityIndexesFromRight[i][j];
                const modifiedIndexFromRight = Math.min(playerStates[i].board.length, indexFromRight);
                handlePostDeathrattleEffect(deadEntity, indexFromRight, deadEntities, deadEntityPlayerState, otherPlayerState, deathrattleInput.gameState, entitiesFromDeathrattles, deadEntityPlayerState.player.friendly, deathrattleInput);
            }
        }
    }
};
const handleDeathrattles = (deathrattleInput) => {
    (0, exports.orchestrateMinionDeathEffects)(deathrattleInput, false, false);
};
exports.handleDeathrattles = handleDeathrattles;
const handlePostDeathrattleEffect = (deadEntity, indexFromRight, deadEntities, deadEntityPlayerState, otherPlayerState, gameState, spawnedEntities, isPlayer, deathrattleInput) => {
    var _a;
    const entityRightToSpawns = indexFromRight === 0 ? null : deadEntityPlayerState.board[deadEntityPlayerState.board.length - indexFromRight];
    spawnedEntities.forEach((entity) => {
        var _a;
        entity.hasAttacked = deadEntity.hasAttacked > 1 ? 1 : (_a = entityRightToSpawns === null || entityRightToSpawns === void 0 ? void 0 : entityRightToSpawns.hasAttacked) !== null && _a !== void 0 ? _a : 0;
    });
    if ((_a = deadEntityPlayerState.player.questRewards) === null || _a === void 0 ? void 0 : _a.includes("BG24_Reward_113")) {
        const ogDeadEntity = gameState.sharedState.deaths.find((entity) => entity.entityId === deadEntity.entityId);
        if (ogDeadEntity) {
            ogDeadEntity.attack += 4;
            ogDeadEntity.health += 4;
        }
    }
    if (deadEntityPlayerState.player.globalInfo.HauntedCarapaceAttackBonus > 0) {
        deadEntity.attack = Math.max(0, deadEntity.attack - deadEntityPlayerState.player.globalInfo.HauntedCarapaceAttackBonus);
    }
    if (deadEntityPlayerState.player.globalInfo.HauntedCarapaceHealthBonus > 0) {
        deadEntity.health = Math.max(1, deadEntity.health - deadEntityPlayerState.player.globalInfo.HauntedCarapaceHealthBonus);
    }
    if ((0, utils_1.hasCorrectTribe)(deadEntity, deadEntityPlayerState.player, reference_data_1.Race.UNDEAD, gameState.anomalies, gameState.allCards)) {
        if (deadEntityPlayerState.player.globalInfo.UndeadAttackBonus > 0) {
            deadEntity.attack = Math.max(0, deadEntity.attack - deadEntityPlayerState.player.globalInfo.UndeadAttackBonus);
        }
    }
    if ((0, utils_1.hasCorrectTribe)(deadEntity, deadEntityPlayerState.player, reference_data_1.Race.BEAST, gameState.anomalies, gameState.allCards)) {
        if (deadEntityPlayerState.player.globalInfo.GoldrinnBuffAtk > 0) {
            deadEntity.attack = Math.max(0, deadEntity.attack - deadEntityPlayerState.player.globalInfo.GoldrinnBuffAtk);
        }
    }
};
//# sourceMappingURL=deathrattle-orchestration.js.map