//#region src/preview/QualityUpgradeScheduler.ts
var QualityUpgradeScheduler = class {
	#maxConcurrent;
	#queue = [];
	#activeTasks = /* @__PURE__ */ new Map();
	#completedTasks = /* @__PURE__ */ new Map();
	#abortController;
	#requestFrameRender;
	#isCached;
	constructor(options) {
		this.#requestFrameRender = options.requestFrameRender;
		this.#maxConcurrent = options.maxConcurrent ?? 4;
		this.#isCached = options.isCached;
		this.#abortController = new AbortController();
	}
	/**
	* Add tasks without affecting existing ones (additive).
	* Used for lookahead extension during playback.
	*/
	enqueue(tasks) {
		if (this.#abortController.signal.aborted) return;
		for (const task of tasks) {
			if (this.#queue.some((t) => t.key === task.key) || this.#activeTasks.has(task.key) || this.#completedTasks.has(task.key)) continue;
			this.#queue.push(task);
		}
		this.#queue.sort((a, b) => a.deadlineMs - b.deadlineMs);
		this.#processQueue();
	}
	/**
	* Replace all queued tasks for an owner.
	* Used on seeks, trim changes, timeline position changes where old deadlines are stale.
	* Does NOT cancel in-flight tasks (they populate shared cache).
	*/
	replaceForOwner(owner, tasks) {
		if (this.#abortController.signal.aborted) return;
		this.#queue = this.#queue.filter((t) => t.owner !== owner);
		for (const task of tasks) {
			if (this.#activeTasks.has(task.key)) continue;
			this.#queue.push(task);
		}
		this.#queue.sort((a, b) => a.deadlineMs - b.deadlineMs);
		this.#processQueue();
	}
	/**
	* Cancel all tasks for an owner.
	* Removes queued tasks. Does NOT abort in-flight fetches.
	*/
	cancelForOwner(owner) {
		this.#queue = this.#queue.filter((t) => t.owner !== owner);
		for (const [key, task] of this.#completedTasks.entries()) if (task.owner === owner) this.#completedTasks.delete(key);
	}
	/**
	* Process the queue - start tasks up to maxConcurrent limit.
	*/
	#processQueue() {
		if (this.#abortController.signal.aborted) return;
		while (this.#activeTasks.size < this.#maxConcurrent && this.#queue.length > 0) {
			const task = this.#queue.shift();
			if (!task) break;
			if (this.#isCached?.(task.key)) {
				this.#completedTasks.set(task.key, {
					key: task.key,
					owner: task.owner,
					status: "completed"
				});
				continue;
			}
			this.#startTask(task);
		}
	}
	/**
	* Start a single task.
	*/
	#startTask(task) {
		const promise = task.fetch(this.#abortController.signal).then(() => {
			this.#activeTasks.delete(task.key);
			this.#completedTasks.set(task.key, {
				key: task.key,
				owner: task.owner,
				status: "completed"
			});
			this.#requestFrameRender();
			this.#processQueue();
		}).catch((error) => {
			this.#activeTasks.delete(task.key);
			if (!(error instanceof DOMException && error.name === "AbortError")) this.#completedTasks.set(task.key, {
				key: task.key,
				owner: task.owner,
				status: "failed",
				error: error instanceof Error ? error.message : String(error)
			});
			this.#processQueue();
		});
		this.#activeTasks.set(task.key, {
			task,
			startedAt: performance.now(),
			promise
		});
	}
	/**
	* Check whether a task is currently in-flight (started, not yet complete).
	*/
	isActive(key) {
		return this.#activeTasks.has(key);
	}
	/**
	* Check whether a task is waiting in the queue (submitted but not yet started).
	*/
	isPending(key) {
		return this.#queue.some((t) => t.key === key);
	}
	/**
	* Get snapshot of current queue state for debugging.
	*/
	getQueueSnapshot() {
		const results = [];
		for (const task of this.#queue) results.push({
			key: task.key,
			owner: task.owner,
			deadlineMs: task.deadlineMs,
			status: "queued"
		});
		for (const [key, activeTask] of this.#activeTasks.entries()) results.push({
			key,
			owner: activeTask.task.owner,
			deadlineMs: activeTask.task.deadlineMs,
			status: "active"
		});
		for (const [key, completed] of this.#completedTasks.entries()) results.push({
			key,
			owner: completed.owner,
			deadlineMs: 0,
			status: completed.status,
			error: completed.error
		});
		return results;
	}
	/**
	* Get progress for a specific owner.
	*/
	getOwnerProgress(owner) {
		const queued = this.#queue.filter((t) => t.owner === owner).length;
		let active = 0;
		for (const activeTask of this.#activeTasks.values()) if (activeTask.task.owner === owner) active++;
		let completed = 0;
		let failed = 0;
		for (const task of this.#completedTasks.values()) if (task.owner === owner) if (task.status === "completed") completed++;
		else failed++;
		return {
			queued,
			active,
			completed,
			failed
		};
	}
	/**
	* Dispose the scheduler - abort all in-flight work.
	*/
	dispose() {
		for (const activeTask of this.#activeTasks.values()) activeTask.promise.catch(() => {});
		this.#abortController.abort();
		this.#queue = [];
		this.#activeTasks.clear();
		this.#completedTasks.clear();
	}
};

//#endregion
export { QualityUpgradeScheduler };
//# sourceMappingURL=QualityUpgradeScheduler.js.map