"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "setupProbeScheduler", {
    enumerable: true,
    get: function() {
        return setupProbeScheduler;
    }
});
const _usecacheprobeglobals = require("./use-cache-probe-globals");
const PROBE_THRESHOLD_MS = 10000;
const MIN_PROBE_BUDGET_MS = 3000;
function setupProbeScheduler(opts) {
    const { workStore, outerRequestStore, cacheContext, encodedArguments, fillDeadlineAt, stream, abortSignal, onProbeCompleted } = opts;
    if (fillDeadlineAt - performance.now() < PROBE_THRESHOLD_MS + MIN_PROBE_BUDGET_MS) {
        return stream;
    }
    const probe = (0, _usecacheprobeglobals.getUseCacheProbe)();
    if (!probe) {
        return stream;
    }
    let lastChunkAt = performance.now();
    let idleTimer;
    const startProbe = ()=>{
        if (abortSignal.aborted) {
            return;
        }
        const probeStartedAtChunk = lastChunkAt;
        // Computed when the probe is about to run so it gets the actual remaining
        // budget, not a stale value baked in at scheduler setup. Reserves a 1s
        // buffer so the probe's internal timeout fires before the outer render
        // timeout.
        const probeInternalTimeoutMs = fillDeadlineAt - performance.now() - 1000;
        probe({
            page: workStore.page,
            route: workStore.route,
            id: cacheContext.functionId,
            kind: cacheContext.handlerKind,
            encodedArguments,
            // Built lazily because most fills complete before the idle timer fires;
            // only worth assembling once we know the probe is running.
            request: {
                headers: Array.from(outerRequestStore.headers.entries()),
                cookieHeader: outerRequestStore.headers.get('cookie') ?? undefined,
                urlPathname: outerRequestStore.url.pathname,
                urlSearch: outerRequestStore.url.search,
                rootParams: outerRequestStore.rootParams ?? {},
                isDraftMode: workStore.isDraftMode ?? false,
                isHmrRefresh: outerRequestStore.isHmrRefresh ?? false,
                hmrRefreshHash: outerRequestStore.hmrRefreshHash
            },
            timeoutMs: probeInternalTimeoutMs
        }).then((completed)=>{
            // Mid-probe recovery: chunks arrived while the probe was running, so
            // the main stream is making progress. Discard the probe's result rather
            // than reporting a deadlock that no longer holds.
            if (lastChunkAt > probeStartedAtChunk) {
                return;
            }
            if (completed && !abortSignal.aborted) {
                onProbeCompleted();
            }
        }, ()=>{
        // Probe failures are inconclusive; fall back to the regular cache-fill
        // timeout.
        });
    };
    const scheduleAfterIdle = ()=>{
        if (idleTimer !== undefined || abortSignal.aborted) {
            return;
        }
        const now = performance.now();
        const idleFor = now - lastChunkAt;
        const wait = Math.max(0, PROBE_THRESHOLD_MS - idleFor);
        // Skip scheduling if the outer fill timeout will fire before the probe
        // could even start running with at least a minimum useful budget. Without
        // this check, a chunk arriving late in the fill could reschedule a probe
        // that the outer timeout would then abort — wasted worker spawn for a probe
        // that can't meaningfully complete.
        if (fillDeadlineAt - now < wait + MIN_PROBE_BUDGET_MS) {
            return;
        }
        idleTimer = setTimeout(()=>{
            idleTimer = undefined;
            if (abortSignal.aborted) {
                return;
            }
            const idleNow = performance.now() - lastChunkAt;
            if (idleNow < PROBE_THRESHOLD_MS) {
                // A chunk arrived since we set this timer; reschedule.
                scheduleAfterIdle();
                return;
            }
            startProbe();
        }, wait);
    };
    abortSignal.addEventListener('abort', ()=>{
        if (idleTimer !== undefined) {
            clearTimeout(idleTimer);
            idleTimer = undefined;
        }
    }, {
        once: true
    });
    scheduleAfterIdle();
    return stream.pipeThrough(new TransformStream({
        transform (chunk, controller) {
            lastChunkAt = performance.now();
            scheduleAfterIdle();
            controller.enqueue(chunk);
        }
    }));
}

//# sourceMappingURL=use-cache-probe-scheduler.js.map