import { Graph } from "../graph";
import { Component } from "../lib/Component";
import { Emitter } from "../utils/Emitter";
import { IPoint, TRect } from "../utils/types/shapes";
export interface IWithHitTest {
    hitBox: IHitBox;
    zIndex: number;
    setHitBox(minX: number, minY: number, maxX: number, maxY: number, force?: boolean): void;
    onHitBox(shape: HitBoxData): boolean;
    removeHitBox(): void;
}
export type HitBoxData = {
    minX: number;
    minY: number;
    maxX: number;
    maxY: number;
    x: number;
    y: number;
};
export interface IHitBox extends HitBoxData {
    update(minX: number, minY: number, maxX: number, maxY: number): void;
    destroy(): void;
    getRect(): [number, number, number, number];
}
/**
 * Hit Testing system with dual architecture for performance optimization:
 *
 * 1. interactiveTree (RBush) - for fast spatial search of elements on click/hover
 * 2. usableRectTracker (IncrementalBoundingBoxTracker) - for optimized calculation of overall bbox
 *
 * This solution allows:
 * - Avoid circular dependencies with boundary elements (affectsUsableRect: false)
 * - Optimize performance for different types of operations
 * - Efficiently handle high-frequency updates (drag operations up to 120fps)
 *
 * Performance benchmark results:
 * - Multiple blocks drag: +62% faster than naive approach 🏆
 * - Single block drag: equal performance
 * - Solution to the problem of recalculating usableRect on every change
 */
export declare class HitTest extends Emitter {
    protected graph: Graph;
    private interactiveTree;
    private usableRectTracker;
    readonly $usableRect: import("@preact/signals-core").Signal<TRect>;
    private readonly $pendingEntitiesUpdate;
    protected queue: Map<HitBox, HitBoxData>;
    constructor(graph: Graph);
    /**
     * Check if graph has any elements (blocks or connections)
     * @returns true if graph has elements, false if empty
     */
    private hasGraphElements;
    get isUnstable(): boolean;
    /**
     * Load array of HitBox items
     * @param items Array of HitBox items to load
     * @returns void
     */
    load(items: HitBox[]): void;
    protected processQueue: (() => void) & {
        cancel: () => void;
        flush: () => void;
        isScheduled: () => boolean;
    };
    /**
     * Update HitBox item with new bounds
     * @param item HitBox item to update
     * @param bbox New bounds data
     * @param _force Force update flag
     * @returns void
     */
    update(item: HitBox, bbox: HitBoxData, _force?: boolean): void;
    /**
     * Clear all HitBox items and reset state
     */
    clear(): void;
    /**
     * Mark hitTest as pending an entity update (called by setEntities).
     * Makes isUnstable = true until processQueue completes.
     * Does NOT clear usableRectTracker — existing data stays valid.
     * Does NOT eagerly schedule processQueue — it fires naturally when hitbox
     * updates arrive (new components register) or when updateBlock forces a hitbox
     * refresh on existing components. Eager scheduling caused processQueue to run
     * in the same rAF frame as markPendingUpdate (before MEDIUM/component renders),
     * clearing $pendingEntitiesUpdate before new block hitboxes were queued.
     */
    markPendingUpdate(): void;
    /**
     * Add new HitBox item
     * @param item HitBox item to add
     */
    add(item: HitBox): void;
    /**
     * Wait for usableRect to become stable and then call callback
     * @param callback Function to call when usableRect becomes stable
     * @returns Unsubscribe function
     */
    waitUsableRectUpdate(callback: (rect: TRect) => void): () => void;
    protected updateUsableRect(): void;
    /**
     * Remove HitBox item
     * @param item HitBox item to remove
     */
    remove(item: HitBox): void;
    /**
     * Test hit at specific point
     * @param point Point to test
     * @param pixelRatio Pixel ratio for coordinate conversion
     * @returns Array of hit components
     */
    testPoint(point: IPoint, pixelRatio: number): Component[];
    /**
     * Test hit box intersection with interactive elements
     * @param item Hit box data to test
     * @returns Array of hit components
     */
    testBox(item: Omit<HitBoxData, "x" | "y">): Component[];
    /**
     * Subscribe to usableRect updates
     * @param callback Function to call when usableRect changes
     * @returns Unsubscribe function
     */
    onUsableRectUpdate(callback: (rect: TRect) => void): () => void;
    /**
     * Get current usableRect value
     * @returns Current usableRect
     */
    getUsableRect(): TRect;
    destroy(): void;
    /**
     * Test hit box intersection with interactive elements and sort by z-index
     * @param item Hit box data to test
     * @returns Array of hit components sorted by z-index
     */
    /**
     * Test hit box intersection with interactive elements and sort by z-index
     * @param item Hit box data to test
     * @returns Array of hit components sorted by z-index
     */
    testHitBox(item: HitBoxData): Component[];
}
export declare class HitBox implements IHitBox {
    item: {
        affectsUsableRect?: boolean;
    } & {
        zIndex: number;
    } & Component & IWithHitTest;
    protected hitTest: HitTest;
    destroyed: boolean;
    maxX: number;
    maxY: number;
    minX: number;
    minY: number;
    x: number;
    y: number;
    /**
     * AffectsUsableRect flag uses to determine if the element affects the usableRect
     * If true, the element will be added to the usableRect tracker
     * if false, the element wont affect the usableRect
     */
    affectsUsableRect: boolean;
    private rect;
    protected unstable: boolean;
    constructor(item: {
        affectsUsableRect?: boolean;
    } & {
        zIndex: number;
    } & Component & IWithHitTest, hitTest: HitTest);
    /**
     * Update HitBox rectangle data
     * @param rect New rectangle data
     */
    updateRect(rect: HitBoxData): void;
    /**
     * Update HitBox bounds
     * @param minX Minimum X coordinate
     * @param minY Minimum Y coordinate
     * @param maxX Maximum X coordinate
     * @param maxY Maximum Y coordinate
     * @param force Force update even if bounds haven't changed
     */
    update: (minX: number, minY: number, maxX: number, maxY: number, force?: boolean) => void;
    /**
     * Get HitBox rectangle as array [x, y, width, height]
     * @returns Rectangle array [x, y, width, height]
     */
    getRect(): [number, number, number, number];
    /**
     * Remove HitBox from hit testing
     */
    remove(): void;
    /**
     * Destroy HitBox and remove from hit testing
     */
    destroy(): void;
    setAffectsUsableRect(affectsUsableRect: boolean): void;
}
