import { seededRandom } from "../../../../../core/math/random/seededRandom.js";
import { GridCellAction } from "../../GridCellAction.js";
import { assert } from "../../../../../core/assert.js";
import { binarySearchHighIndex } from "../../../../../core/collection/array/binarySearchHighIndex.js";
import { number_compare_ascending } from "../../../../../core/primitives/numbers/number_compare_ascending.js";

/**
 *
 * @type {number[]}
 */
const evaluatedWeights = [];

export class CellActionSelectWeightedRandom extends GridCellAction {

    /**
     *
     * @type {function}
     * @private
     */
    __random = seededRandom(0);

    /**
     *
     * @type {WeightedGridCellAction[]}
     */
    options = [];


    /**
     *
     * @param {WeightedGridCellAction[]} options
     * @returns {CellActionSelectWeightedRandom}
     */
    static from(options) {
        const r = new CellActionSelectWeightedRandom();

        r.addManyOptions(options);


        return r;
    }

    /**
     *
     * @param {WeightedGridCellAction[]} options
     */
    addManyOptions(options) {
        const n = options.length;
        for (let i = 0; i < n; i++) {
            const action = options[i];

            this.addOption(action);
        }
    }

    /**
     *
     * @param {WeightedGridCellAction} option
     */
    addOption(option) {
        assert.equal(option.isWeightedGridCellAction, true, 'option.isWeightedGridCellAction !== true');

        this.options.push(option);
    }

    initialize(data, seed) {
        this.__random.setCurrentSeed(seed);

        const actions = this.options;
        const n = actions.length;

        for (let i = 0; i < n; i++) {
            const weightedGridCellAction = actions[i];

            weightedGridCellAction.initialize(data, seed);
        }
    }

    execute(data, x, y, rotation) {
        const elements = this.options;
        const n = elements.length;

        let totalWeight = 0;


        for (let i = 0; i < n; i++) {
            /**
             *
             * @type {WeightedGridCellAction}
             */
            const weightedElement = elements[i];

            /**
             *
             * @type {CellFilter}
             */
            const weightFilter = weightedElement.weight;

            const weightValue = weightFilter.execute(data, x, y, 0);


            if (weightValue > 0) {
                //if the weight is negative, we clamp it to 0

                totalWeight += weightValue;
            }

            evaluatedWeights[i] = totalWeight;

        }

        const targetWeight = this.__random() * totalWeight;

        const index = binarySearchHighIndex(evaluatedWeights, targetWeight, number_compare_ascending, 0, n - 1);

        const targetElement = elements[index];

        targetElement.action.execute(data, x, y, rotation);
    }
}
