import { ShadedGeometry } from "../../ShadedGeometry.js";
import { ShadedGeometryFlags } from "../../ShadedGeometryFlags.js";

export class RuntimeDrawMethodOptimizer {
    constructor() {

        /**
         *
         * @type {ShadedGeometrySystem|null}
         * @private
         */
        this.__system = null;

        /**
         *
         * @type {Generator<number>}
         * @private
         */
        this.__entity_iterator = null;
    }

    /**
     *
     * @returns {boolean} true if a change was made, false otherwise
     */
    step() {
        const system = this.__system;

        if (system === null) {
            return false;
        }

        const ecd = system.entityManager.dataset;

        if (ecd === null) {
            // no dataset attached
            return false;
        }

        if (!ecd.isComponentTypeRegistered(ShadedGeometry)) {
            // component not registered
            return false;
        }

        if (this.__entity_iterator === null) {
            this.__entity_iterator = ecd[Symbol.iterator]();
        }

        const next = this.__entity_iterator.next();

        if (next.done) {
            this.__entity_iterator = ecd[Symbol.iterator]();
            return false;
        }

        const entity = next.value;

        if (!ecd.entityExists(entity)) {
            // seems that iterator is stale, reset iterator
            this.__entity_iterator = null;
            return false;
        }

        /**
         *
         * @type {ShadedGeometry}
         */
        const sg = ecd.getComponent(entity, ShadedGeometry);

        if (sg === undefined) {
            return false;
        }

        if (sg.getFlag(ShadedGeometryFlags.DrawMethodLocked)) {
            // draw mode is locked, can't change
            return false;
        }

        const use_count = system.getGeometryUsageCounters().get(sg.geometry.id);

        /**
         *
         * @type {ShadedGeometryRendererContext|undefined}
         */
        const first_context = system.__view_contexts.values().next().value;

        if (first_context === undefined) {
            return false;
        }

        const adapters = first_context.adapters;
        const adapter_count = adapters.length;

        let best_score = Number.NEGATIVE_INFINITY;
        let best_adapter = -1;

        for (let i = 0; i < adapter_count; i++) {
            const adapter = adapters[i];

            const score = adapter.score(sg.geometry, sg.material, use_count);

            if (score > best_score) {
                best_score = score;
                best_adapter = i;
            }
        }

        if (best_adapter === -1) {
            // not found
            return false;
        }

        if (sg.draw_method === best_adapter) {
            return false;
        }

        if (!adapters[best_adapter].intend_draw(sg)) {
            // unable to draw, don't do anything
            return false;
        }

        sg.draw_method = best_adapter;

        return true;
    }
}
