"use strict";
/*!
 * Copyright (c) 2026-present, Vanilagy and contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.sendCommand = exports.unrefWorker = exports.refWorker = void 0;
const shared_1 = require("./shared");
// @ts-expect-error An esbuild plugin handles this, TypeScript doesn't need to understand
const codec_worker_1 = __importDefault(require("./codec.worker"));
let workerPromise;
let nextMessageId = 0;
const pendingMessages = new Map();
let refCount = 0;
let keepAliveInterval = null;
const refWorker = async () => {
    refCount++;
    if (refCount === 1) {
        keepAliveInterval = setInterval(() => { }, 2 ** 31 - 1);
        const worker = await ensureWorker();
        worker.ref?.();
    }
};
exports.refWorker = refWorker;
const unrefWorker = async () => {
    refCount--;
    if (refCount === 0) {
        if (keepAliveInterval !== null) {
            clearInterval(keepAliveInterval);
            keepAliveInterval = null;
        }
        const worker = await workerPromise;
        if (worker) {
            if (worker.unref) {
                worker.unref(); // If we don't do this, then the Node process never terminates by itself
            }
            else if (typeof window === 'undefined') {
                // Non-browser environment without unref - terminate instead
                worker.terminate();
                workerPromise = null;
            }
        }
    }
};
exports.unrefWorker = unrefWorker;
const sendCommand = async (command, transferables) => {
    const worker = await ensureWorker();
    return new Promise((resolve, reject) => {
        const id = nextMessageId++;
        pendingMessages.set(id, {
            resolve: resolve,
            reject,
        });
        if (transferables) {
            worker.postMessage({ id, command }, transferables);
        }
        else {
            worker.postMessage({ id, command });
        }
    });
};
exports.sendCommand = sendCommand;
const ensureWorker = () => {
    return workerPromise ??= (async () => {
        // eslint-disable-next-line @typescript-eslint/no-unsafe-call
        const worker = (await (0, codec_worker_1.default)());
        worker.unref?.(); // Start unreffed
        const onMessage = (data) => {
            const pending = pendingMessages.get(data.id);
            (0, shared_1.assert)(pending !== undefined);
            pendingMessages.delete(data.id);
            if (data.success) {
                pending.resolve(data.data);
            }
            else {
                pending.reject(data.error);
            }
        };
        if (worker.addEventListener) {
            worker.addEventListener('message', event => onMessage(event.data));
        }
        else {
            const nodeWorker = worker;
            nodeWorker.on('message', onMessage);
        }
        return worker;
    })();
};
