import { DragContext, DragDiff } from "../../../services/drag";
import { BlockState } from "../../../store/block/Block";
import { TGroup, TGroupId } from "../../../store/group/Group";
import { TRect } from "../../../utils/types/shapes";
import { Group, TGroupGeometry, TGroupStyle } from "./Group";
declare module "../../../graphEvents" {
    interface GraphEventsDefinitions {
        "group-collapse-change": (event: CustomEvent<{
            groupId: TGroupId;
            collapsed: boolean;
            currentRect: TRect;
            nextRect: TRect;
        }>) => void;
    }
}
/** A single collapse direction axis value. */
export type TCollapseDirection = "start" | "center" | "end";
export interface TCollapsibleGroup extends TGroup {
    /** Whether this group is currently collapsed */
    collapsed?: boolean;
    /**
     * The visual rect used when collapsed. When set, the group renders and
     * responds to hit-tests using this rect instead of the normal `rect`.
     *
     * `rect` itself continues to be managed by `withBlockGrouping` (or
     * manually) and always reflects the real block bounding box.
     */
    collapsedRect?: TRect;
    /**
     * Where the collapsed header appears relative to the full group rect.
     *
     * - `x`: `"start"` → left edge  |  `"center"` → centered  |  `"end"` → right edge
     * - `y`: `"start"` → top edge   |  `"center"` → centered  |  `"end"` → bottom edge
     *
     * Defaults to `{ x: "start", y: "start" }` (top-left corner).
     *
     * Only used by the default collapse rect computation. Ignored when
     * {@link getCollapseRect} is provided.
     */
    collapseDirection?: {
        x?: TCollapseDirection;
        y?: TCollapseDirection;
    };
    /**
     * User-defined function to compute the collapsed rect from the expanded rect.
     *
     * When not provided, a default implementation computes a
     * {@link DEFAULT_COLLAPSED_WIDTH}×{@link DEFAULT_COLLAPSED_HEIGHT} rect
     * pinned at the position determined by {@link collapseDirection}.
     *
     * @example
     * ```typescript
     * const group: TCollapsibleGroup = {
     *   id: "my-group",
     *   rect: { x: 0, y: 0, width: 400, height: 300 },
     *   component: CollapsibleGroup,
     *   getCollapseRect: (_group, rect) => ({
     *     x: rect.x + rect.width / 2 - 100,
     *     y: rect.y,
     *     width: 200,
     *     height: 48,
     *   }),
     * };
     * ```
     */
    getCollapseRect?: (group: TCollapsibleGroup, expandedRect: TRect) => TRect;
}
/**
 * Default collapse rect computation. Produces a rect of the given size
 * pinned at the position determined by `direction`.
 *
 * Exported so users can call it from their custom `getCollapseRect` and
 * extend or modify the default behavior.
 *
 * @param expandedRect - The full group rect before collapsing.
 * @param direction - Where the header is pinned (defaults to top-left).
 * @param collapsedWidth - Header width (defaults to 200).
 * @param collapsedHeight - Header height (defaults to 48).
 */
export declare function computeDefaultCollapseRect(expandedRect: TRect, direction?: {
    x?: TCollapseDirection;
    y?: TCollapseDirection;
}, collapsedWidth?: number, collapsedHeight?: number): TRect;
/**
 * Cached result of {@link CollapsibleGroup.getPortDelegationCounts}; invalidated
 * when delegation membership changes (delegate/undelegate), not when rects move.
 */
type TPortDelegationCounts = {
    left: number;
    right: number;
};
export declare class CollapsibleGroup<T extends TCollapsibleGroup = TCollapsibleGroup> extends Group<T> {
    /** Snapshot of `collapsedRect` at drag start; see {@link handleDrag}. */
    private dragStartCollapsedRect;
    /**
     * Lazily computed delegation counts for {@link renderCollapsedView}; cleared when
     * delegation changes (delegate/undelegate ports).
     */
    private portDelegationCountsCache;
    static define(config: {
        style?: Partial<TGroupStyle>;
        geometry?: Partial<TGroupGeometry>;
    }): typeof CollapsibleGroup;
    /**
     * Extend base subscription to also react to collapsed state on init.
     * subscribeSignal fires immediately with the current value, so a group
     * that starts with collapsed: true will hide its blocks on mount.
     *
     * Also handles external collapse state changes: if setGroups() is called
     * with collapsed: false while the group is currently collapsed, it expands.
     */
    protected subscribeToGroup(): ReturnType<Group["subscribeToGroup"]>;
    /**
     * Returns the visual rect. When collapsed, returns `collapsedRect`
     * (with padding) so the group renders as a compact header.
     */
    protected getRect(rect?: TRect): TRect;
    /**
     * Sets the hitbox to the collapsed rect when collapsed, or the expanded
     * rect otherwise. Passes the raw inner rect to super so that base Group's
     * updateHitBox can apply padding exactly once.
     */
    protected updateHitBox(rect: TRect): void;
    /**
     * Remember inner rect and collapsed rect so {@link handleDrag} can translate
     * `collapsedRect` by the same snapped delta as `rect` (grid snapping in Group).
     */
    handleDragStart(context: DragContext): void;
    handleDragEnd(context: DragContext): void;
    /**
     * When dragging a collapsed group, move `collapsedRect` in lockstep with the snapped
     * `rect` movement computed by {@link Group.handleDrag} (not per-frame mouse deltas).
     */
    handleDrag(diff: DragDiff, context: DragContext): void;
    /** Whether this group is currently in the collapsed state. */
    isCollapsed(): boolean;
    protected getGroupBlocks(): BlockState[];
    /**
     * Returns the number of ports currently delegated to the left and right
     * group edge ports. Only meaningful when the group is collapsed.
     *
     * Cost is O(blocks × anchors) per call when the cache is cold — typical group
     * sizes keep this cheap. The result is cached until delegation changes
     * ({@link delegatePorts} / {@link undelegatePorts}); override {@link renderCollapsedView}
     * and call a custom counter if you need different invalidation rules.
     */
    protected getPortDelegationCounts(): TPortDelegationCounts;
    private invalidatePortDelegationCountsCache;
    /**
     * Compute the collapsed rect for a given full rect.
     *
     * Uses the user-provided `getCollapseRect` if available, otherwise falls
     * back to the direction-based default.
     */
    private computeCollapsedRect;
    /**
     * Collapse the group: set collapsedRect, hide member blocks,
     * and redirect their ports to the group edges.
     *
     * Emits a cancelable `group-collapse-change` event before applying changes.
     * If a listener calls `event.preventDefault()`, the collapse is cancelled.
     */
    collapse(): void;
    /**
     * Expand the group: remove collapsedRect, show member blocks, and let
     * them resume managing their own ports.
     *
     * Emits a cancelable `group-collapse-change` event before applying changes.
     * If a listener calls `event.preventDefault()`, the expand is cancelled.
     */
    expand(): void;
    protected unmount(): void;
    private applyBlockVisibility;
    /**
     * Get (or create) the group's left-edge port used as a delegation target.
     * Input ports and IN anchors delegate to this port when collapsed.
     */
    private getLeftEdgePort;
    /**
     * Get (or create) the group's right-edge port used as a delegation target.
     * Output ports and OUT anchors delegate to this port when collapsed.
     */
    private getRightEdgePort;
    /**
     * Update the group's edge port positions to match the given rect.
     */
    private updateGroupPortPositions;
    /**
     * Delegate all ports of group blocks to the group's edge ports.
     *
     * - Input port  → left-edge port
     * - Output port → right-edge port
     * - IN anchors  → left-edge port
     * - OUT anchors → right-edge port
     *
     * While delegated, block ports mirror the group edge positions.
     * When the group is dragged, only the group edge ports need to be
     * updated — all delegated ports follow automatically.
     */
    private delegatePorts;
    /**
     * Remove delegation from all ports of group blocks, restoring their
     * original positions (saved automatically by the delegation mechanism).
     */
    private undelegatePorts;
    protected render(): void;
    /**
     * Render the compact header shown when the group is collapsed.
     * Override this method to customise the collapsed appearance.
     */
    protected renderCollapsedView(ctx: CanvasRenderingContext2D): void;
}
export {};
