export const EDIT_OPERATION_TERMINAL_EVENT = "parhelia:edit-operation-terminal";
const TERMINAL_RESULT_CACHE_KEY = "__parheliaEditOperationTerminalResults";
const TERMINAL_RESULT_TTL_MS = 5 * 60 * 1000;
export function editOperationNeedsTerminalCompletion(result) {
    if (result.errorMessage)
        return false;
    const ids = result.createdItemIds;
    if (Array.isArray(ids) && ids.length > 0)
        return false;
    const type = String(result.type ?? "");
    if (type === "copy-items" || type === "clone-items")
        return true;
    return (result.executionStatus === "executing" || result.isLongRunning === true);
}
export const copyItemsNeedsTerminalCompletion = editOperationNeedsTerminalCompletion;
export function normalizeOpId(id) {
    return String(id).replace(/[{}]/g, "").toLowerCase();
}
function getTerminalResultCache() {
    if (typeof window === "undefined") {
        return new Map();
    }
    const target = window;
    if (!target[TERMINAL_RESULT_CACHE_KEY]) {
        target[TERMINAL_RESULT_CACHE_KEY] = new Map();
    }
    return target[TERMINAL_RESULT_CACHE_KEY];
}
function pruneTerminalResultCache(cache, now) {
    for (const [key, value] of cache.entries()) {
        if (now - value.storedAt > TERMINAL_RESULT_TTL_MS) {
            cache.delete(key);
        }
    }
}
function getCachedEditOperationTerminalResult(operationId) {
    if (typeof window === "undefined")
        return undefined;
    const cache = getTerminalResultCache();
    const now = Date.now();
    pruneTerminalResultCache(cache, now);
    return cache.get(normalizeOpId(operationId))?.result;
}
export function cacheEditOperationTerminalResult(detail) {
    if (typeof window === "undefined")
        return;
    const operationId = detail.operationId ?? detail.id;
    if (!operationId)
        return;
    const cache = getTerminalResultCache();
    const now = Date.now();
    pruneTerminalResultCache(cache, now);
    cache.set(normalizeOpId(operationId), {
        result: {
            createdItemIds: detail.createdItemIds,
            errorMessage: detail.errorMessage,
            successCount: detail.successCount,
            failureCount: detail.failureCount,
            results: detail.results,
            summary: detail.summary,
        },
        storedAt: now,
    });
}
// How often the HTTP fallback polls the operation status. The socket event is
// still the fast path; polling only matters when the realtime message never
// arrives (e.g. the Settings workspace, which has no page-scoped connection).
const TERMINAL_POLL_INTERVAL_MS = 1500;
/**
 * Polls GET /parhelia/editOperation?id= until the operation reaches a terminal
 * status. The long-running executor persists executionStatus + createdItemIds
 * to the store before it broadcasts, so this is authoritative even when the
 * broadcast is not delivered.
 */
async function fetchEditOperationTerminal(operationId) {
    if (typeof fetch === "undefined")
        return undefined;
    try {
        const response = await fetch(`/parhelia/editOperation?id=${encodeURIComponent(operationId)}`, {
            method: "GET",
            credentials: "include",
            headers: { "Cache-Control": "no-cache" },
        });
        // 404 while the row is not yet written — keep polling.
        if (!response.ok)
            return undefined;
        const op = (await response.json());
        const status = String(op.executionStatus ?? "").toLowerCase();
        if (status === "completed") {
            return {
                createdItemIds: op.createdItemIds,
                successCount: op.successCount,
                failureCount: op.failureCount,
                results: op.results,
                summary: op.summary,
            };
        }
        if (status === "failed") {
            return {
                errorMessage: op.errorMessage ?? "Operation failed",
                summary: op.summary,
            };
        }
        return undefined;
    }
    catch {
        return undefined;
    }
}
export function waitForEditOperationTerminal(operationId, timeoutMs) {
    const want = normalizeOpId(operationId);
    const cachedResult = getCachedEditOperationTerminalResult(want);
    if (cachedResult) {
        return Promise.resolve(cachedResult);
    }
    return new Promise((resolve, reject) => {
        let settled = false;
        const cleanup = () => {
            window.removeEventListener(EDIT_OPERATION_TERMINAL_EVENT, handler);
            clearTimeout(timeout);
            clearInterval(pollTimer);
        };
        const finish = (result) => {
            if (settled)
                return;
            settled = true;
            cleanup();
            resolve(result);
        };
        const timeout = setTimeout(() => {
            if (settled)
                return;
            settled = true;
            cleanup();
            reject(new Error("Operation timed out"));
        }, timeoutMs);
        const handler = (ev) => {
            const d = ev.detail;
            const oid = d.operationId ?? d.id;
            if (!oid || normalizeOpId(oid) !== want)
                return;
            finish({
                createdItemIds: d.createdItemIds,
                errorMessage: d.errorMessage,
                successCount: d.successCount,
                failureCount: d.failureCount,
                results: d.results,
                summary: d.summary,
            });
        };
        window.addEventListener(EDIT_OPERATION_TERMINAL_EVENT, handler);
        // HTTP fallback: the socket event is preferred, but it is not delivered in
        // every workspace, so poll the persisted operation status in parallel.
        const pollTimer = setInterval(() => {
            void fetchEditOperationTerminal(operationId).then((result) => {
                if (result)
                    finish(result);
            });
        }, TERMINAL_POLL_INTERVAL_MS);
    });
}
//# sourceMappingURL=waitForEditOperationTerminal.js.map