import { assert } from "../../core/assert.js";
import Vector2 from "../../core/geom/Vector2.js";
import { CellFilterLiteralFloat } from "../filtering/numeric/CellFilterLiteralFloat.js";
import { GridCellActionSequence } from "./action/util/GridCellActionSequence.js";

export class GridCellPlacementRule {
    /**
     *
     * @type {CellMatcher}
     */
    pattern = null;

    /**
     *
     * @type {CellFilter}
     */
    probability = CellFilterLiteralFloat.from(1);

    /**
     *
     * @type {Vector2}
     */
    positionOffset = new Vector2();


    /**
     *
     * @type {GridCellAction}
     */
    action = null;

    /**
     *
     * @type {boolean}
     */
    allowRotation = true;

    /**
     *
     * @param {CellMatcher} matcher
     * @param {GridCellAction[]} [actions]
     * @param {GridCellAction} action
     * @param {number|CellFilter} [probability]
     * @param {Vector2} [offset]
     * @param {boolean} [allowRotation]
     * @returns {GridCellPlacementRule}
     */
    static from({
                    matcher,
                    actions,
                    action = GridCellActionSequence.from(actions),
                    probability = CellFilterLiteralFloat.from(1),
                    offset = Vector2.zero,
                    allowRotation = true
                }) {

        assert.defined(matcher);
        assert.defined(action);

        const r = new GridCellPlacementRule();

        r.pattern = matcher;

        r.action = action;

        if (actions !== undefined) {
            console.warn(`"actions" parameter is deprecated. Use a sequence instead`);
            assert.isArray(actions, 'actions');
        }

        assert.equal(probability.isCellFilter, true, 'probability.isCellFilter !== true');

        r.probability = probability;

        r.positionOffset.copy(offset);

        r.allowRotation = allowRotation;

        return r;
    }

    /**
     *
     * @param {GridData} grid
     * @param {number} seed
     */
    initialize(grid, seed) {

        this.action.initialize(grid, seed);

        this.pattern.initialize(grid, seed);

        if (!this.probability.initialized) {
            this.probability.initialize(grid, seed);
        }
    }

    /**
     * Write placement tags into the grid at a given position, the tag pattern will be rotated as specified
     * @param {GridData} grid
     * @param {number} x
     * @param {number} y
     * @param {number} rotation in Radians
     */
    execute(grid, x, y, rotation) {
        const sin = Math.sin(rotation);
        const cos = Math.cos(rotation);

        const offset = this.positionOffset;

        const local_x = offset.x;
        const local_y = offset.y;

        const rotated_local_x = local_x * cos - local_y * sin
        const rotated_local_y = local_x * sin + local_y * cos;

        this.action.execute(grid, x + rotated_local_x, y + rotated_local_y, rotation);

    }
}
