import { MultiMap } from "../utils/collections.js";
var DefaultLangiumProfiler = class {
	constructor(t) {
		this.activeCategories = /* @__PURE__ */ new Set(), this.allCategories = new Set([
			"validating",
			"parsing",
			"linking"
		]), this.activeCategories = t ?? new Set(this.allCategories), this.records = new MultiMap();
	}
	isActive(e) {
		return this.activeCategories.has(e);
	}
	start(...e) {
		e ? e.forEach((e) => this.activeCategories.add(e)) : this.activeCategories = new Set(this.allCategories);
	}
	stop(...e) {
		e ? e.forEach((e) => this.activeCategories.delete(e)) : this.activeCategories.clear();
	}
	createTask(e, t) {
		if (!this.isActive(e)) throw Error(`Category "${e}" is not active.`);
		return console.log(`Creating profiling task for '${e}.${t}'.`), new ProfilingTask((t) => this.records.add(e, this.dumpRecord(e, t)), t);
	}
	dumpRecord(e, t) {
		console.info(`Task ${e}.${t.identifier} executed in ${t.duration.toFixed(2)}ms and ended at ${t.date.toISOString()}`);
		let n = [];
		for (let e of t.entries.keys()) {
			let r = t.entries.get(e), i = r.reduce((e, t) => e + t);
			n.push({
				name: `${t.identifier}.${e}`,
				count: r.length,
				duration: i
			});
		}
		let r = t.duration - n.map((e) => e.duration).reduce((e, t) => e + t, 0);
		n.push({
			name: t.identifier,
			count: 1,
			duration: r
		}), n.sort((e, t) => t.duration - e.duration);
		function i(e) {
			return Math.round(100 * e) / 100;
		}
		return console.table(n.map((e) => ({
			Element: e.name,
			Count: e.count,
			"Self %": i(100 * e.duration / t.duration),
			"Time (ms)": i(e.duration)
		}))), t;
	}
	getRecords(...e) {
		return e.length === 0 ? this.records.values() : this.records.entries().filter((t) => e.some((e) => e === t[0])).flatMap((e) => e[1]);
	}
}, ProfilingTask = class {
	constructor(t, n) {
		this.stack = [], this.entries = new MultiMap(), this.addRecord = t, this.identifier = n;
	}
	start() {
		if (this.startTime !== void 0) throw Error(`Task "${this.identifier}" is already started.`);
		this.startTime = performance.now();
	}
	stop() {
		if (this.startTime === void 0) throw Error(`Task "${this.identifier}" was not started.`);
		if (this.stack.length !== 0) throw Error(`Task "${this.identifier}" cannot be stopped before sub-task(s): ${this.stack.map((e) => e.id).join(", ")}.`);
		let e = {
			identifier: this.identifier,
			date: /* @__PURE__ */ new Date(),
			duration: performance.now() - this.startTime,
			entries: this.entries
		};
		this.addRecord(e), this.startTime = void 0, this.entries.clear();
	}
	startSubTask(e) {
		this.stack.push({
			id: e,
			start: performance.now(),
			content: 0
		});
	}
	stopSubTask(e) {
		let t = this.stack.pop();
		if (!t) throw Error(`Task "${this.identifier}.${e}" was not started.`);
		if (t.id !== e) throw Error(`Sub-Task "${t.id}" is not already stopped.`);
		let n = performance.now() - t.start;
		this.stack.at(-1) !== void 0 && (this.stack[this.stack.length - 1].content += n);
		let r = n - t.content;
		this.entries.add(e, r);
	}
};
export { DefaultLangiumProfiler, ProfilingTask };
