import { ValidationError } from "../core/index.js";
import {} from "./Component.js";
import { entityKey } from "./Entity.js";
import {} from "./World.js";
export class CommandBuffer {
    nextTempId = 1;
    commands = [];
    createEntity() {
        const ref = { tempId: this.nextTempId };
        this.nextTempId += 1;
        this.commands.push({ kind: "create", tempId: ref.tempId });
        return ref;
    }
    destroyEntity(entity) {
        this.commands.push({ kind: "destroy", entity });
    }
    add(entity, ctor, component) {
        this.commands.push({ kind: "add", entity, ctor, component });
    }
    remove(entity, ctor) {
        this.commands.push({ kind: "remove", entity, ctor });
    }
    flush(world) {
        validateCommands(world, this.commands);
        const tempEntities = new Map();
        const created = [];
        const commands = this.commands.splice(0, this.commands.length);
        for (const command of commands) {
            if (command.kind === "create") {
                const entity = world.createEntity();
                tempEntities.set(command.tempId, entity);
                created.push(entity);
                continue;
            }
            const entity = resolve(command.entity, tempEntities);
            if (command.kind === "destroy")
                world.destroyEntity(entity);
            if (command.kind === "add")
                world.add(entity, command.ctor, command.component);
            if (command.kind === "remove")
                world.remove(entity, command.ctor);
        }
        return created;
    }
}
function validateCommands(world, commands) {
    const tempAlive = new Set();
    const deadEntities = new Set();
    for (const command of commands) {
        if (command.kind === "create") {
            tempAlive.add(command.tempId);
            continue;
        }
        validateEntityRef(world, command.entity, tempAlive, deadEntities);
        if (command.kind === "remove")
            world.registry.require(command.ctor);
        if (command.kind === "destroy") {
            if ("tempId" in command.entity) {
                tempAlive.delete(command.entity.tempId);
            }
            else {
                deadEntities.add(entityKey(command.entity));
            }
        }
    }
}
function validateEntityRef(world, ref, tempAlive, deadEntities) {
    if ("tempId" in ref) {
        if (!tempAlive.has(ref.tempId))
            throw new ValidationError("TEMP_ENTITY", `Temporary entity is not alive: ${ref.tempId}`);
        return;
    }
    world.assertAlive(ref);
    if (deadEntities.has(entityKey(ref)))
        throw new ValidationError("ENTITY_NOT_ALIVE", `Entity was already destroyed by this command buffer: ${entityKey(ref)}`);
}
function resolve(ref, tempEntities) {
    if ("tempId" in ref) {
        const entity = tempEntities.get(ref.tempId);
        if (!entity)
            throw new ValidationError("TEMP_ENTITY", `Temporary entity was not created: ${ref.tempId}`);
        return entity;
    }
    return ref;
}
//# sourceMappingURL=CommandBuffer.js.map