/**
 * Fuse.js v7.4.2 - Lightweight fuzzy-search (http://fusejs.io)
 *
 * Copyright (c) 2026 Kiro Risk (http://kiro.me)
 * All Rights Reserved. Apache Software License 2.0
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 */
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });

//#region src/core/errorMessages.ts
const FUSE_WORKER_UNSUPPORTED_FN_OPTION = (option) => `FuseWorker does not support function-valued option '${option}': functions cannot be transferred to Web Workers via postMessage. Remove this option or fall back to Fuse.`;
const FUSE_WORKER_TOKEN_SEARCH_UNSUPPORTED = "FuseWorker does not support useTokenSearch: token search depends on corpus-level statistics (df, fieldCount) that are computed per shard, so per-shard scores would diverge from single-thread Fuse. Use Fuse on the main thread for token search.";

//#endregion
//#region src/workers/FuseWorker.ts
const DEFAULT_MAX_WORKERS = 8;
function getDefaultWorkerCount() {
	const hw = typeof navigator !== "undefined" ? navigator.hardwareConcurrency || 4 : 4;
	return Math.min(hw, DEFAULT_MAX_WORKERS);
}
const browserWorkerBase = typeof document !== "undefined" ? document.currentScript?.src || new URL("fuse-worker.cjs", document.baseURI).href : void 0;
function resolveDefaultWorkerUrl() {
	if (browserWorkerBase !== void 0) return new URL("./fuse.worker.mjs", browserWorkerBase);
	try {
		return new URL("./fuse.worker.mjs", require("url").pathToFileURL(__filename).href);
	} catch {
		if (browserWorkerBase !== void 0) return new URL("./fuse.worker.mjs", browserWorkerBase);
		throw new Error("FuseWorker: unable to resolve the worker script URL automatically; pass workerOptions.workerUrl explicitly.");
	}
}
var FuseWorker = class FuseWorker {
	constructor(docs, options, workerOptions) {
		this._shards = null;
		this._addCursor = 0;
		this._initPromise = null;
		this._pending = /* @__PURE__ */ new Map();
		this._nextId = 0;
		this._docs = docs.slice();
		this._options = options || {};
		this._workerOptions = workerOptions || {};
		FuseWorker._assertNoFunctionOptions(this._options);
		if (this._options.useTokenSearch) throw new Error(FUSE_WORKER_TOKEN_SEARCH_UNSUPPORTED);
		this._workerUrl = this._workerOptions.workerUrl || resolveDefaultWorkerUrl();
	}
	static _assertNoFunctionOptions(options) {
		if (typeof options.sortFn === "function") throw new Error(FUSE_WORKER_UNSUPPORTED_FN_OPTION("sortFn"));
		if (typeof options.getFn === "function") throw new Error(FUSE_WORKER_UNSUPPORTED_FN_OPTION("getFn"));
		if (typeof options.tokenize === "function") throw new Error(FUSE_WORKER_UNSUPPORTED_FN_OPTION("tokenize"));
		const keys = options.keys;
		if (Array.isArray(keys)) for (let i = 0, len = keys.length; i < len; i += 1) {
			const key = keys[i];
			if (key && typeof key === "object" && !Array.isArray(key)) {
				if (typeof key.getFn === "function") {
					const name = key.name;
					const label = Array.isArray(name) ? name.join(".") : name ?? String(i);
					throw new Error(FUSE_WORKER_UNSUPPORTED_FN_OPTION(`keys[${label}].getFn`));
				}
			}
		}
	}
	_getNumWorkers() {
		return this._workerOptions.numWorkers || getDefaultWorkerCount();
	}
	_ensureInit() {
		if (this._initPromise) return this._initPromise;
		this._initPromise = this._init();
		return this._initPromise;
	}
	_spawnWorker() {
		const worker = new Worker(this._workerUrl, { type: "module" });
		worker.onmessage = (e) => {
			const { id, result, error } = e.data;
			const handler = this._pending.get(id);
			if (!handler) return;
			this._pending.delete(id);
			if (error) handler.reject(new Error(error));
			else handler.resolve(result);
		};
		worker.onerror = (e) => {
			for (const [, handler] of this._pending) handler.reject(new Error(e.message));
		};
		return worker;
	}
	_workerInitOptions() {
		return {
			...this._options,
			includeScore: true
		};
	}
	async _init() {
		const numWorkers = this._getNumWorkers();
		const chunkSize = Math.ceil(this._docs.length / numWorkers);
		this._shards = [];
		this._addCursor = 0;
		const workerInitOptions = this._workerInitOptions();
		const initPromises = [];
		for (let i = 0; i < numWorkers; i++) {
			const start = i * chunkSize;
			const end = Math.min(start + chunkSize, this._docs.length);
			const chunk = this._docs.slice(start, end);
			const globalIndices = [];
			for (let j = start; j < end; j += 1) globalIndices.push(j);
			const shard = {
				worker: this._spawnWorker(),
				globalIndices
			};
			this._shards.push(shard);
			initPromises.push(this._call(shard.worker, "init", [chunk, workerInitOptions]));
		}
		await Promise.all(initPromises);
	}
	_call(worker, method, args) {
		const id = this._nextId++;
		return new Promise((resolve, reject) => {
			this._pending.set(id, {
				resolve,
				reject
			});
			worker.postMessage({
				id,
				method,
				args
			});
		});
	}
	async search(query, options) {
		await this._ensureInit();
		const shards = this._shards;
		const results = await Promise.all(shards.map((s) => this._call(s.worker, "search", [query, options])));
		const merged = [];
		for (let i = 0, len = results.length; i < len; i += 1) {
			const { globalIndices } = shards[i];
			for (const r of results[i]) merged.push({
				...r,
				refIndex: globalIndices[r.refIndex]
			});
		}
		if (this._options.shouldSort !== false) merged.sort((a, b) => {
			const sa = a.score ?? 0;
			const sb = b.score ?? 0;
			if (sa === sb) return a.refIndex < b.refIndex ? -1 : 1;
			return sa < sb ? -1 : 1;
		});
		else merged.sort((a, b) => a.refIndex - b.refIndex);
		if (!this._options.includeScore) for (let i = 0, len = merged.length; i < len; i += 1) {
			const r = merged[i];
			merged[i] = r.matches !== void 0 ? {
				item: r.item,
				refIndex: r.refIndex,
				matches: r.matches
			} : {
				item: r.item,
				refIndex: r.refIndex
			};
		}
		const limit = options?.limit;
		if (limit && limit > 0) return merged.slice(0, limit);
		return merged;
	}
	async add(doc) {
		await this._ensureInit();
		const shards = this._shards;
		const shard = shards[this._addCursor % shards.length];
		this._addCursor += 1;
		const globalIdx = this._docs.length;
		this._docs.push(doc);
		shard.globalIndices.push(globalIdx);
		await this._call(shard.worker, "add", [doc]);
	}
	async setCollection(docs) {
		this._docs = docs.slice();
		if (!this._shards) {
			this._initPromise = null;
			return;
		}
		const shards = this._shards;
		const chunkSize = Math.ceil(this._docs.length / shards.length);
		this._addCursor = 0;
		const tasks = [];
		for (let i = 0, len = shards.length; i < len; i += 1) {
			const start = i * chunkSize;
			const end = Math.min(start + chunkSize, this._docs.length);
			const chunk = this._docs.slice(start, end);
			const globalIndices = [];
			for (let j = start; j < end; j += 1) globalIndices.push(j);
			shards[i].globalIndices = globalIndices;
			tasks.push(this._call(shards[i].worker, "setCollection", [chunk]));
		}
		await Promise.all(tasks);
	}
	terminate() {
		if (this._shards) {
			for (const { worker } of this._shards) worker.terminate();
			this._shards = null;
		}
		this._initPromise = null;
		for (const [, handler] of this._pending) handler.reject(/* @__PURE__ */ new Error("FuseWorker terminated"));
		this._pending.clear();
	}
};

//#endregion
exports.FuseWorker = FuseWorker;