import * as Comlink from 'comlink';
/**
 * Wraps a provided instance of {@link AsyncDatabaseConnection}, providing necessary proxy
 * functions for worker listeners.
 */
export class WorkerWrappedAsyncDatabaseConnection {
    options;
    lockAbortController;
    constructor(options) {
        this.options = options;
        this.lockAbortController = new AbortController();
    }
    get baseConnection() {
        return this.options.baseConnection;
    }
    init() {
        return this.baseConnection.init();
    }
    /**
     * Get a MessagePort which can be used to share the internals of this connection.
     */
    async shareConnection() {
        const { identifier, remote } = this.options;
        /**
         * Hold a navigator lock in order to avoid features such as Chrome's frozen tabs,
         * or Edge's sleeping tabs from pausing the thread for this connection.
         * This promise resolves once a lock is obtained.
         * This lock will be held as long as this connection is open.
         * The `shareConnection` method should not be called on multiple tabs concurrently.
         */
        await new Promise((resolve, reject) => navigator.locks
            .request(`shared-connection-${this.options.identifier}-${Date.now()}-${Math.round(Math.random() * 10000)}`, {
            signal: this.lockAbortController.signal
        }, async () => {
            resolve();
            // Free the lock when the connection is already closed.
            if (this.lockAbortController.signal.aborted) {
                return;
            }
            // Hold the lock while the shared connection is in use.
            await new Promise((releaseLock) => {
                this.lockAbortController.signal.addEventListener('abort', () => {
                    releaseLock();
                });
            });
        })
            // We aren't concerned with abort errors here
            .catch((ex) => {
            if (ex.name == 'AbortError') {
                resolve();
            }
            else {
                reject(ex);
            }
        }));
        const newPort = await remote[Comlink.createEndpoint]();
        return { port: newPort, identifier };
    }
    /**
     * Registers a table change notification callback with the base database.
     * This can be extended by custom implementations in order to handle proxy events.
     */
    async registerOnTableChange(callback) {
        return this.baseConnection.registerOnTableChange(Comlink.proxy(callback));
    }
    async close() {
        // Abort any pending lock requests.
        this.lockAbortController.abort();
        await this.baseConnection.close();
        this.options.remote[Comlink.releaseProxy]();
        this.options.onClose?.();
    }
    execute(sql, params) {
        return this.baseConnection.execute(sql, params);
    }
    executeRaw(sql, params) {
        return this.baseConnection.executeRaw(sql, params);
    }
    executeBatch(sql, params) {
        return this.baseConnection.executeBatch(sql, params);
    }
    getConfig() {
        return this.baseConnection.getConfig();
    }
}
