import { LRUCache } from "../utils/LRUCache.js";

//#region src/preview/RenderContext.ts
/**
* Check if an element has a renderVersion property.
*/
function hasRenderVersion(element) {
	return "renderVersion" in element && typeof element.renderVersion === "number";
}
/**
* Module-level counter for generating unique element IDs.
* This ensures uniqueness across all RenderContext instances.
*/
let nextElementId = 1;
/**
* WeakMap to store unique IDs for elements.
* Using WeakMap ensures we don't prevent garbage collection of elements.
* The ID is stable for the lifetime of the element.
*/
const elementUniqueIds = /* @__PURE__ */ new WeakMap();
/**
* Get or create a unique ID for an element.
* This guarantees uniqueness even for elements with the same id attribute
* or no id attribute at all.
*/
function getElementUniqueId(element) {
	let id = elementUniqueIds.get(element);
	if (id === void 0) {
		id = nextElementId++;
		elementUniqueIds.set(element, id);
	}
	return id;
}
/**
* RenderContext provides scoped caching for render operations.
*
* Create at the start of a render, dispose when complete:
* ```typescript
* const context = new RenderContext();
* try {
*   // ... render operations
* } finally {
*   context.dispose();
* }
* ```
*/
var RenderContext = class {
	/** Cache for static element canvases (ef-image, ef-waveform) */
	#canvasCache;
	/** Cache for video frames by source timestamp */
	#videoFrameCache;
	/** Cache for document styles (computed once per render session) */
	#documentStylesCache = null;
	/** Whether this context has been disposed */
	#disposed = false;
	/** Metrics for monitoring cache effectiveness */
	#metrics = {
		canvasCacheHits: 0,
		canvasCacheMisses: 0,
		videoFrameCacheHits: 0,
		videoFrameCacheMisses: 0
	};
	constructor(options = {}) {
		const { maxCanvasCacheSize = 50, maxVideoFrameCacheSize = 100 } = options;
		this.#canvasCache = new LRUCache(maxCanvasCacheSize);
		this.#videoFrameCache = new LRUCache(maxVideoFrameCacheSize);
	}
	/**
	* Check if the context has been disposed.
	*/
	get disposed() {
		return this.#disposed;
	}
	/**
	* Get cache metrics for monitoring.
	*/
	get metrics() {
		return { ...this.#metrics };
	}
	/**
	* Generate a cache key for a static element.
	* Uses a unique element ID (via WeakMap) to ensure uniqueness even if
	* multiple elements have the same id attribute.
	* Returns null if the element doesn't support caching (no renderVersion).
	*/
	#getCanvasCacheKey(element) {
		if (!hasRenderVersion(element)) return null;
		return `canvas:${getElementUniqueId(element)}:${element.renderVersion}`;
	}
	/**
	* Get a cached dataURL for a static element.
	* Returns undefined if not cached or element doesn't support caching.
	*/
	getCachedCanvasDataUrl(element) {
		if (this.#disposed) return void 0;
		const key = this.#getCanvasCacheKey(element);
		if (!key) return void 0;
		const cached = this.#canvasCache.get(key);
		if (cached) this.#metrics.canvasCacheHits++;
		else this.#metrics.canvasCacheMisses++;
		return cached;
	}
	/**
	* Cache a dataURL for a static element.
	* Does nothing if the element doesn't support caching.
	*/
	setCachedCanvasDataUrl(element, dataUrl) {
		if (this.#disposed) return;
		const key = this.#getCanvasCacheKey(element);
		if (key) this.#canvasCache.set(key, dataUrl);
	}
	/**
	* Generate a cache key for a video frame.
	* Uses a unique element ID (via WeakMap) to ensure uniqueness even if
	* multiple videos have the same id attribute.
	*/
	#getVideoFrameCacheKey(videoElement, sourceTimeMs) {
		return `video:${getElementUniqueId(videoElement)}:${Math.round(sourceTimeMs)}`;
	}
	/**
	* Get a cached video frame.
	* Returns undefined if not cached.
	*/
	getCachedVideoFrame(videoElement, sourceTimeMs) {
		if (this.#disposed) return void 0;
		const key = this.#getVideoFrameCacheKey(videoElement, sourceTimeMs);
		const cached = this.#videoFrameCache.get(key);
		if (cached) this.#metrics.videoFrameCacheHits++;
		else this.#metrics.videoFrameCacheMisses++;
		return cached;
	}
	/**
	* Cache a video frame.
	*/
	setCachedVideoFrame(videoElement, sourceTimeMs, frame) {
		if (this.#disposed) return;
		const key = this.#getVideoFrameCacheKey(videoElement, sourceTimeMs);
		this.#videoFrameCache.set(key, frame);
	}
	/**
	* Convenience method to get or capture a video frame.
	* Checks cache first, then captures if not cached.
	*
	* @param video - The ef-video element
	* @param sourceTimeMs - Source media timestamp
	* @param options - Capture options including quality and signal
	* @returns The captured frame data
	*/
	async getOrCaptureVideoFrame(video, sourceTimeMs, options = {}) {
		const cached = this.getCachedVideoFrame(video, sourceTimeMs);
		if (cached) return cached;
		const frame = await video.captureFrameAtSourceTime(sourceTimeMs, options);
		this.setCachedVideoFrame(video, sourceTimeMs, frame);
		return frame;
	}
	/**
	* Get cached document styles.
	* Returns undefined if not cached.
	*/
	getCachedDocumentStyles() {
		if (this.#disposed) return void 0;
		return this.#documentStylesCache ?? void 0;
	}
	/**
	* Cache document styles.
	*/
	setCachedDocumentStyles(styles) {
		if (this.#disposed) return;
		this.#documentStylesCache = styles;
	}
	/**
	* Dispose the context and clear all caches.
	* Should be called when rendering is complete.
	*/
	dispose() {
		if (this.#disposed) return;
		this.#canvasCache.clear();
		this.#videoFrameCache.clear();
		this.#documentStylesCache = null;
		this.#disposed = true;
	}
	/**
	* Symbol.dispose implementation for use with the `using` keyword.
	*
	* @example
	* ```typescript
	* using context = new RenderContext();
	* // ... render operations
	* // context is automatically disposed when scope exits
	* ```
	*/
	[Symbol.dispose]() {
		this.dispose();
	}
	/**
	* Get the current size of the canvas cache.
	*/
	get canvasCacheSize() {
		return this.#canvasCache.size;
	}
	/**
	* Get the current size of the video frame cache.
	*/
	get videoFrameCacheSize() {
		return this.#videoFrameCache.size;
	}
};

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