"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CustomItemPools = void 0;
const isaac_typescript_definitions_1 = require("isaac-typescript-definitions");
const decorators_1 = require("../../../decorators");
const ModCallbackCustom_1 = require("../../../enums/ModCallbackCustom");
const array_1 = require("../../../functions/array");
const map_1 = require("../../../functions/map");
const utils_1 = require("../../../functions/utils");
const weighted_1 = require("../../../functions/weighted");
const ReadonlyMap_1 = require("../../../types/ReadonlyMap");
const Feature_1 = require("../../private/Feature");
const v = {
    run: {
        customItemPools: new ReadonlyMap_1.ReadonlyMap(),
    },
};
const customItemPoolMap = new Map();
class CustomItemPools extends Feature_1.Feature {
    /** @internal */
    v = v;
    /** @internal */
    constructor() {
        super();
        this.customCallbacksUsed = [
            [
                ModCallbackCustom_1.ModCallbackCustom.POST_GAME_STARTED_REORDERED,
                this.postGameStartedReorderedFalse,
                [false],
            ],
        ];
    }
    // ModCallbackCustom.POST_GAME_STARTED_REORDERED
    // false
    postGameStartedReorderedFalse = () => {
        v.run.customItemPools = (0, map_1.copyMap)(customItemPoolMap);
    };
    /**
     * Helper function to register a custom item pool. Use this function once when your mod first
     * loads to declare the items that you want to be in the item pools. Then, in the middle of a run,
     * you can use `getCustomItemPoolCollectible`.
     *
     * For example:
     *
     * ```ts
     * const ItemPoolTypeCustom = {
     *   FOO = 0 as ItemPoolType,
     * } as const;
     *
     * const FOO_ITEM_POOL = [
     *   [CollectibleType.SAD_ONION, 1],
     *   [CollectibleType.INNER_EYE, 0.5],
     * ];
     *
     * registerCustomItemPool(ItemPoolTypeCustom.FOO, FOO_ITEM_POOL);
     * ```
     *
     * Note that custom item pools do not currently support partial weight decrementation on sight.
     *
     * In order to use this function, you must upgrade your mod with `ISCFeature.CUSTOM_ITEM_POOLS`.
     *
     * @param itemPoolTypeCustom An integer that identifies what kind of item pool you are creating.
     *                           It should correspond to a local `ItemPoolTypeCustom` enum in your
     *                           mod. The integer can be any unique value and can safely overlap with
     *                           the vanilla item pool type values (or values chosen by other mods).
     * @param collectibles An array of weighted collectible tuples that represent the item pool that
     *                     you are creating. The first element in he tuple is the `CollectibleType`,
     *                     and the second element in the tuple is the float that represents the weight
     *                     of the collectible.
     * @public
     */
    registerCustomItemPool(itemPoolTypeCustom, collectibles) {
        if (customItemPoolMap.has(itemPoolTypeCustom)) {
            error(`Failed to register a custom item pool since the provided type of ${itemPoolTypeCustom} was already registered.`);
        }
        customItemPoolMap.set(itemPoolTypeCustom, collectibles);
    }
    /**
     * Helper function to get a new collectible from a custom item pool created with the
     * `registerCustomItemPool` function. This function has the same format as the
     * `ItemPool.GetCollectible` method.
     *
     * By default, a collectible will not be removed from the pool once it is selected, unless the
     * `decrease` argument is set to true (similar to how a vanilla item pool works).
     *
     * If you want to get an unseeded collectible type, you must explicitly pass `undefined` to the
     * `seedOrRNG` parameter.
     *
     * In order to use this function, you must upgrade your mod with `ISCFeature.CUSTOM_ITEM_POOLS`.
     *
     * @param itemPoolTypeCustom An integer representing the custom item pool to use.
     * @param seedOrRNG The `Seed` or `RNG` object to use. If an `RNG` object is provided, the
     *                  `RNG.Next` method will be called. If `undefined` is provided, it will default
     *                  to a random seed.
     * @param decrease Optional. Whether to remove the selected collectible from the item pool.
     *                 Default is true.
     * @param defaultItem Optional. The collectible to return if the item pool is depleted. Default is
     *                    `CollectibleType.NULL`.
     * @public
     */
    getCustomItemPoolCollectible(itemPoolTypeCustom, seedOrRNG, decrease = false, defaultItem = isaac_typescript_definitions_1.CollectibleType.NULL) {
        const customItemPool = v.run.customItemPools.get(itemPoolTypeCustom);
        (0, utils_1.assertDefined)(customItemPool, `Failed to find the custom item pool of: ${itemPoolTypeCustom}`);
        if (customItemPool.length === 0) {
            return defaultItem;
        }
        const randomIndex = (0, weighted_1.getRandomIndexFromWeightedArray)(customItemPool, seedOrRNG);
        const tuple = customItemPool[randomIndex];
        (0, utils_1.assertDefined)(tuple, `Failed to get an element from a custom item pool using a random index of: ${randomIndex}`);
        if (decrease) {
            (0, array_1.arrayRemoveIndexInPlace)(customItemPool, randomIndex);
        }
        return tuple[0];
    }
}
exports.CustomItemPools = CustomItemPools;
__decorate([
    decorators_1.Exported
], CustomItemPools.prototype, "registerCustomItemPool", null);
__decorate([
    decorators_1.Exported
], CustomItemPools.prototype, "getCustomItemPoolCollectible", null);
