import { assert } from "../../../shared/src/asserts.js";
import { emptyArray } from "../../../shared/src/sentinels.js";
import { skipYields } from "./operator.js";
import { applyChange } from "./view-apply-change.js";
//#region ../zql/src/ivm/array-view.ts
/**
* Implements a materialized view of the output of an operator.
*
* It might seem more efficient to use an immutable b-tree for the
* materialization, but it's not so clear. Inserts in the middle are
* asymptotically slower in an array, but can often be done with zero
* allocations, where changes to the b-tree will often require several allocs.
*
* Also the plain array view is more convenient for consumers since you can dump
* it into console to see what it is, rather than having to iterate it.
*/
var ArrayView = class {
	#input;
	#listeners = /* @__PURE__ */ new Set();
	#schema;
	#format;
	#root;
	onDestroy;
	#dirty = false;
	#resultType = "unknown";
	#error;
	#updateTTL;
	constructor(input, format, queryComplete, updateTTL) {
		this.#input = input;
		this.#schema = input.getSchema();
		this.#format = format;
		this.#updateTTL = updateTTL;
		this.#root = { "": format.singular ? void 0 : [] };
		input.setOutput(this);
		if (queryComplete === true) this.#resultType = "complete";
		else if ("error" in queryComplete) {
			this.#resultType = "error";
			this.#error = queryComplete;
		} else queryComplete.then(() => {
			this.#resultType = "complete";
			this.#fireListeners();
		}).catch((e) => {
			this.#resultType = "error";
			this.#error = e;
			this.#fireListeners();
		});
		this.#hydrate();
	}
	get data() {
		return this.#root[""];
	}
	addListener(listener) {
		assert(!this.#listeners.has(listener), "Listener already registered");
		this.#listeners.add(listener);
		this.#fireListener(listener);
		return () => {
			this.#listeners.delete(listener);
		};
	}
	#fireListeners() {
		for (const listener of this.#listeners) this.#fireListener(listener);
	}
	#fireListener(listener) {
		listener(this.data, this.#resultType, this.#error);
	}
	destroy() {
		this.onDestroy?.();
	}
	#hydrate() {
		this.#dirty = true;
		for (const node of skipYields(this.#input.fetch({}))) applyChange(this.#root, {
			type: "add",
			node
		}, this.#schema, "", this.#format);
		this.flush();
	}
	push(change) {
		this.#dirty = true;
		applyChange(this.#root, change, this.#schema, "", this.#format);
		return emptyArray;
	}
	flush() {
		if (!this.#dirty) return;
		this.#dirty = false;
		this.#fireListeners();
	}
	updateTTL(ttl) {
		this.#updateTTL(ttl);
	}
};
//#endregion
export { ArrayView };

//# sourceMappingURL=array-view.js.map