import { BLOB_CACHE_ENABLED } from "./constant";
class BlobCache {
    cache = new Map();
    pending = new Map();
    /**
     * Generates a cache key from media parameters
     */
    getCacheKey(channel, sessionId, messageId) {
        return `${channel}:${sessionId}:${messageId}`;
    }
    /**
     * Gets a cached blob URL if it exists
     */
    get(channel, sessionId, messageId) {
        if (!BLOB_CACHE_ENABLED)
            return null;
        const key = this.getCacheKey(channel, sessionId, messageId);
        const entry = this.cache.get(key);
        if (entry) {
            // Increment reference count
            entry.refCount++;
            return { url: entry.url, type: entry.type, hasError: entry.hasError };
        }
        return null;
    }
    /**
     * Gets a pending request if it exists
     */
    getPending(channel, sessionId, messageId) {
        if (!BLOB_CACHE_ENABLED)
            return null;
        const key = this.getCacheKey(channel, sessionId, messageId);
        return this.pending.get(key) || null;
    }
    /**
     * Sets a pending request
     */
    setPending(channel, sessionId, messageId, promise) {
        if (!BLOB_CACHE_ENABLED)
            return;
        const key = this.getCacheKey(channel, sessionId, messageId);
        this.pending.set(key, promise);
    }
    /**
     * Clears a pending request
     */
    clearPending(channel, sessionId, messageId) {
        const key = this.getCacheKey(channel, sessionId, messageId);
        this.pending.delete(key);
    }
    /**
     * Stores a blob URL in the cache
     */
    set(channel, sessionId, messageId, url, type) {
        if (!BLOB_CACHE_ENABLED)
            return;
        const key = this.getCacheKey(channel, sessionId, messageId);
        // If entry already exists with the same URL, don't revoke
        const existingEntry = this.cache.get(key);
        if (existingEntry?.url && existingEntry.url !== url) {
            URL.revokeObjectURL(existingEntry.url);
        }
        this.cache.set(key, {
            url,
            type,
            refCount: 1,
            hasError: false,
        });
    }
    /**
     * Marks a media entry as having an error (failed to load)
     */
    setError(channel, sessionId, messageId) {
        if (!BLOB_CACHE_ENABLED)
            return;
        const key = this.getCacheKey(channel, sessionId, messageId);
        this.cache.set(key, {
            url: null,
            type: null,
            refCount: 1,
            hasError: true,
        });
    }
    /**
     * Decrements reference count and optionally revokes the blob URL
     * Returns true if the entry was removed
     */
    release(channel, sessionId, messageId) {
        const key = this.getCacheKey(channel, sessionId, messageId);
        const entry = this.cache.get(key);
        if (entry) {
            entry.refCount--;
            // Keep the blob URL cached even if refCount reaches 0
            // This prevents re-fetching when scrolling back to the same message
            // Only revoke when explicitly cleared or cache is full
            return false;
        }
        return false;
    }
    /**
     * Clears all cached blob URLs
     */
    clear() {
        this.cache.forEach(entry => {
            if (entry.url) {
                URL.revokeObjectURL(entry.url);
            }
        });
        this.cache.clear();
    }
    /**
     * Gets the current cache size
     */
    size() {
        return this.cache.size;
    }
    /**
     * Removes least recently used entries if cache exceeds size limit
     */
    cleanup(maxSize = 100) {
        if (this.cache.size <= maxSize) {
            return;
        }
        const entriesToRemove = this.cache.size - maxSize;
        let removed = 0;
        // Remove entries with lowest refCount first
        const sortedEntries = Array.from(this.cache.entries())
            .sort((a, b) => a[1].refCount - b[1].refCount);
        for (const [key, entry] of sortedEntries) {
            if (removed >= entriesToRemove) {
                break;
            }
            if (entry.url) {
                URL.revokeObjectURL(entry.url);
            }
            this.cache.delete(key);
            removed++;
        }
    }
}
// Export a singleton instance
export const blobCache = new BlobCache();
