import { FlowBlock } from '../../../../../../layout-engine/contracts/src/index.js';
import { PMNode } from './types.js';
export type CachedParagraphEntry = {
    /** JSON string of the PM node for equality comparison */
    nodeJson?: string;
    /** Optional revision number for fast equality comparison */
    nodeRev?: number | null;
    /** All FlowBlocks produced from this paragraph (may include page breaks, drawings, etc.) */
    blocks: FlowBlock[];
    /** The PM document position where this paragraph node started */
    pmStart: number;
};
export type FlowBlockCacheStats = {
    hits: number;
    misses: number;
};
/**
 * Result of a cache lookup. Always includes the serialized node JSON
 * to avoid double serialization when storing on cache miss.
 */
export type CacheLookupResult = {
    /** The cached entry if found and content matches, null otherwise */
    entry: CachedParagraphEntry | null;
    /** Pre-computed JSON string of the node (reuse this in set() to avoid double serialization) */
    nodeJson?: string;
    /** Parsed node revision (if present) */
    nodeRev?: number | null;
};
export declare class FlowBlockCache {
    #private;
    /**
     * Begin a new render cycle. Clears the "next" map and resets stats.
     */
    begin(): void;
    /**
     * Signal that external changes (e.g. Y.js collaboration) may have modified
     * document content without updating sdBlockRev. When set, the fast revision
     * comparison falls through to a JSON equality check to prevent false cache hits.
     *
     * The flag is automatically cleared after {@link commit}.
     */
    setHasExternalChanges(value: boolean): void;
    /**
     * Look up cached blocks for a paragraph by its stable ID.
     * Returns the cached entry only if the node content matches.
     *
     * Uses a dual comparison strategy:
     * 1. Fast path: compare sdBlockRev numbers (O(1)). A different rev is a
     *    definitive miss. A matching rev is a hit **only** when we trust that
     *    sdBlockRev is always incremented for content changes (i.e. no external
     *    changes pending).
     * 2. JSON path: full node serialization + string comparison. Used as a
     *    safety net when external changes may have bypassed the revision counter
     *    (e.g. Y.js-origin collaboration transactions) or when revision info is
     *    unavailable.
     *
     * Always returns the serialized nodeJson to avoid double serialization -
     * pass this to set() instead of the node object.
     *
     * @param id - Stable paragraph ID (sdBlockId or paraId)
     * @param node - Current PM node (JSON object) to compare against cached version
     * @returns Lookup result with entry (if hit) and pre-computed nodeJson
     */
    get(id: string, node: PMNode): CacheLookupResult;
    /**
     * Store converted blocks for a paragraph in the cache.
     *
     * @param id - Stable paragraph ID
     * @param nodeJson - Pre-computed JSON string of the node (from get() result)
     * @param blocks - All FlowBlocks produced from this paragraph
     * @param pmStart - PM document position where this paragraph starts
     */
    set(id: string, nodeJson: string | undefined, nodeRev: number | null | undefined, blocks: FlowBlock[], pmStart: number): void;
    /**
     * Commit the current render cycle.
     * Swaps "next" to "previous", so only blocks seen in this render are retained.
     * Clears the external-changes flag since the render cycle consumed it.
     */
    commit(): void;
    /**
     * Clear the entire cache.
     * Call this on document load or when conversion settings change.
     */
    clear(): void;
    /**
     * Get cache statistics for the current render cycle.
     */
    get stats(): FlowBlockCacheStats;
}
/**
 * Shift PM positions in a single block by a delta.
 *
 * When reusing cached blocks, the paragraph's position in the document may have
 * shifted (e.g., text was inserted earlier in the doc). This function adjusts
 * the pmStart/pmEnd values to reflect the new position.
 *
 * Always returns a shallow copy to prevent cache pollution from downstream mutations.
 *
 * PM positions may be stored in different locations depending on block type:
 * - Paragraph blocks: positions in each run (run.pmStart, run.pmEnd)
 * - Atomic blocks (image, drawing): positions in attrs (block.attrs.pmStart, block.attrs.pmEnd)
 * - Other blocks: positions at block level (block.pmStart, block.pmEnd)
 *
 * @param block - The block to shift
 * @param delta - The position delta (newPmStart - oldPmStart)
 * @returns A new block (shallow copy) with shifted positions
 */
export declare function shiftBlockPositions(block: FlowBlock, delta: number): FlowBlock;
/**
 * Shift PM positions in all blocks from a cached entry by a delta.
 *
 * @param blocks - Array of blocks to shift
 * @param delta - The position delta (newPmStart - oldPmStart)
 * @returns New array of blocks with shifted positions
 */
export declare function shiftCachedBlocks(blocks: FlowBlock[], delta: number): FlowBlock[];
/**
 * Extract stable paragraph ID from PM node attributes.
 *
 * Uses sdBlockId (preferred) or paraId (fallback) from the node's attrs.
 * These IDs are stable across edits and are used as cache keys.
 *
 * @param node - PM node (JSON object) to extract ID from
 * @returns Stable ID string, or null if no stable ID is available
 */
export declare function getStableParagraphId(node: PMNode): string | null;
//# sourceMappingURL=cache.d.ts.map