import { anySignal } from 'any-signal';
import { setMaxListeners } from 'main-event';
import { debounce } from "./debounce.js";
export function repeatingTask(fn, interval, options) {
    let timeout;
    let shutdownController;
    let running = false;
    function runTask() {
        const opts = {
            signal: shutdownController.signal
        };
        let signal;
        if (options?.timeout != null) {
            signal = anySignal([shutdownController.signal, AbortSignal.timeout(options.timeout)]);
            setMaxListeners(Infinity, signal);
            opts.signal = signal;
        }
        running = true;
        Promise.resolve().then(async () => {
            await fn(opts);
        })
            .catch(() => { })
            .finally(() => {
            if (signal != null) {
                if (signal.aborted) {
                    signal.clear();
                }
                else {
                    // Clear listeners once this per-run signal eventually aborts
                    signal.addEventListener('abort', () => {
                        signal.clear();
                    }, { once: true });
                }
            }
            running = false;
            if (shutdownController.signal.aborted) {
                // task has been cancelled, bail
                return;
            }
            // reschedule
            timeout = setTimeout(runTask, interval);
        });
    }
    const runTaskDebounced = debounce(runTask, options?.debounce ?? 100);
    let started = false;
    return {
        setInterval: (ms) => {
            if (interval === ms) {
                // already running at this interval, nothing to do
                return;
            }
            interval = ms;
            // maybe reschedule
            if (timeout != null) {
                clearTimeout(timeout);
                timeout = setTimeout(runTask, interval);
            }
        },
        setTimeout: (ms) => {
            options ??= {};
            options.timeout = ms;
        },
        run: () => {
            if (running) {
                return;
            }
            clearTimeout(timeout);
            runTaskDebounced();
        },
        start: () => {
            if (started) {
                return;
            }
            started = true;
            shutdownController = new AbortController();
            setMaxListeners(Infinity, shutdownController.signal);
            // run now
            if (options?.runImmediately === true) {
                queueMicrotask(() => {
                    runTask();
                });
            }
            else {
                // run later
                timeout = setTimeout(runTask, interval);
            }
        },
        stop: () => {
            clearTimeout(timeout);
            shutdownController?.abort();
            started = false;
        }
    };
}
//# sourceMappingURL=repeating-task.js.map