import { getRouterContext } from "../router-context.js";
import { debugLog } from "../logging.js";
/**
 * Creates intercept resolution middleware
 *
 * If ctx.interceptResult exists and we're not in a cache-hit-with-intercept scenario:
 * - Resolves intercept segments
 * - Updates state.interceptSegments
 * - Updates state.slots with the intercept slot
 * - Yields intercept segments after main segments
 */
export function withInterceptResolution(ctx, state) {
    return async function* (source) {
        const pipelineStart = performance.now();
        const ms = ctx.metricsStore;
        // First, yield all segments from the source (main segment resolution or cache)
        const segments = [];
        for await (const segment of source) {
            segments.push(segment);
            yield segment;
        }
        // Skip intercept resolution for full match (document requests don't have intercepts)
        if (ctx.isFullMatch) {
            if (ms) {
                ms.metrics.push({ label: "pipeline:intercept", duration: performance.now() - pipelineStart, startTime: pipelineStart - ms.requestStart });
            }
            return;
        }
        // Skip intercept resolution if:
        // 1. No intercept result
        // 2. Already have intercept segments (from cache hit with intercept key)
        // 3. Cache hit with intercept key
        const skipInterceptResolution = !ctx.interceptResult ||
            state.interceptSegments.length > 0 ||
            (state.cacheHit && ctx.isIntercept);
        if (skipInterceptResolution) {
            // For cache hit with intercept, extract intercept segments from cached data for slots
            // and re-resolve loaders for fresh data
            if (ctx.interceptResult && state.cacheHit && ctx.isIntercept) {
                await handleCacheHitIntercept(ctx, state, segments);
            }
            if (ms) {
                ms.metrics.push({ label: "pipeline:intercept", duration: performance.now() - pipelineStart, startTime: pipelineStart - ms.requestStart });
            }
            return;
        }
        // Resolve intercept segments
        const { resolveInterceptEntry } = getRouterContext();
        const slotName = ctx.interceptResult.intercept.slotName;
        debugLog("matchPartial.intercept", "intercept resolved", {
            routeName: ctx.localRouteName,
            slotName,
        });
        // Resolve intercept entry (middleware, loaders, handler)
        const Store = ctx.Store;
        const interceptSegments = await Store.run(() => resolveInterceptEntry(ctx.interceptResult.intercept, ctx.interceptResult.entry, ctx.matched.params, ctx.handlerContext, true, // belongsToRoute
        {
            clientSegmentIds: ctx.clientSegmentSet,
            prevParams: ctx.prevParams,
            request: ctx.request,
            prevUrl: ctx.prevUrl,
            nextUrl: ctx.url,
            routeKey: ctx.routeKey,
            actionContext: ctx.actionContext,
            stale: ctx.stale,
        }));
        // Update state
        state.interceptSegments = interceptSegments;
        state.slots[slotName] = {
            active: true,
            segments: interceptSegments,
        };
        // Yield intercept segments
        for (const segment of interceptSegments) {
            yield segment;
        }
        if (ms) {
            ms.metrics.push({ label: "pipeline:intercept", duration: performance.now() - pipelineStart, startTime: pipelineStart - ms.requestStart });
        }
    };
}
/**
 * Handle cache hit with intercept scenario
 *
 * Extract intercept segments from cached data and re-resolve loaders for fresh data.
 */
async function handleCacheHitIntercept(ctx, state, segments) {
    if (!ctx.interceptResult)
        return;
    const { resolveInterceptLoadersOnly } = getRouterContext();
    const slotName = ctx.interceptResult.intercept.slotName;
    // Find intercept segments from cached segments (namespace starts with "intercept:")
    const interceptSegments = segments.filter((s) => s.namespace?.startsWith("intercept:"));
    state.interceptSegments = interceptSegments;
    // Re-resolve intercept loaders for fresh data on cache hit
    // This keeps cached component/layout but fetches fresh loader data
    if (resolveInterceptLoadersOnly) {
        const Store = ctx.Store;
        const freshLoaderResult = await Store.run(() => resolveInterceptLoadersOnly(ctx.interceptResult.intercept, ctx.interceptResult.entry, ctx.matched.params, ctx.handlerContext, true, // belongsToRoute
        {
            clientSegmentIds: ctx.clientSegmentSet,
            prevParams: ctx.prevParams,
            request: ctx.request,
            prevUrl: ctx.prevUrl,
            nextUrl: ctx.url,
            routeKey: ctx.routeKey,
            actionContext: ctx.actionContext,
            stale: ctx.stale,
        }));
        // Update intercept segment's loaderDataPromise with fresh data
        if (freshLoaderResult) {
            const interceptMainSegment = interceptSegments.find((s) => s.type === "parallel" && s.slot);
            if (interceptMainSegment) {
                interceptMainSegment.loaderDataPromise = freshLoaderResult.loaderDataPromise;
                interceptMainSegment.loaderIds = freshLoaderResult.loaderIds;
                debugLog("matchPartial.intercept", "cache hit with fresh intercept loaders", {
                    routeName: ctx.localRouteName,
                    slotName,
                });
            }
        }
        else {
            debugLog("matchPartial.intercept", "cache hit without intercept loader revalidation", {
                routeName: ctx.localRouteName,
                slotName,
            });
        }
    }
    state.slots[slotName] = {
        active: true,
        segments: interceptSegments,
    };
}
//# sourceMappingURL=intercept-resolution.js.map