import { MirScene } from "../../../../model/game/scenes/MirScene.js";
import { assert } from "../../core/assert.js";
import { EncodingBinaryBuffer } from "../../core/binary/EncodingBinaryBuffer.js";
import { EndianType } from "../../core/binary/EndianType.js";
import { emptyTask } from "../../core/process/task/util/emptyTask.js";
import { GameAssetType } from "../asset/GameAssetType.js";
import BinaryBufferDeSerializer from "../ecs/storage/BinaryBufferDeSerializer.js";

/**
 *
 * @param {string} path
 * @param {EntityComponentDataset} ecd
 * @param {Engine} engine
 * @returns {Promise<void>}
 */
export async function loadSerializedScene(path, ecd, engine) {

    const task = await createSceneDeserializationTask(path, ecd, engine);

    engine.executor.run(task);

    await task.promise();
}

/**
 *
 * @param {string} path
 * @param {EntityComponentDataset} ecd
 * @param {Engine} engine
 * @returns {Promise<Task>}
 */
export async function createSceneDeserializationTask(path, ecd, engine) {
    const assetManager = engine.assetManager;

    const asset = await assetManager.promise(path, GameAssetType.ArrayBuffer)

    /**
     *
     * @type {ArrayBuffer}
     */
    const buffer = asset.create();

    const deSerializer = new BinaryBufferDeSerializer();
    deSerializer.registry = engine.binarySerializationRegistry;

    const binaryBuffer = new EncodingBinaryBuffer();

    binaryBuffer.endianness = EndianType.BigEndian;

    binaryBuffer.fromArrayBuffer(buffer);

    const task = deSerializer.process(binaryBuffer, engine, ecd);

    return task;
}

export class SerializedScene extends MirScene {
    /**
     *
     * @param {string} name Unique scene name
     * @param {string} path Path to serialized scene
     */
    constructor({ name, path }) {
        super(name);

        this.path = path;
    }


    setup(options, engine, success, failure) {
        assert.isFunction(success, 'success');
        assert.isFunction(failure, 'failure');

        this.__engine = engine;

        const ecd = this.dataset;

        //expand dataset to make sure it can take all components
        ecd.setComponentTypeMap(engine.entityManager.getComponentTypeMap());

        loadSerializedScene(this.path, ecd, engine).then(success, failure);

        return emptyTask();
    }
}
