import { Box3, Object3D, Plane, Ray, Vector3 } from "three";
export type { IDragConstraint, IDragConstraintContext } from "./DragControlsConstraints.js";
export { AxisRotationConstraint, GridSnapConstraint, GrabPointPlaneConstraint, KeepRotationConstraint, KeepScaleConstraint, ScaleLimitConstraint, RotationAxis, FixedRotationAxesConstraint, PlaneHeightLockConstraint, SnapToSurfaceConstraint, applyFollowObjectConstraints } from "./DragControlsConstraints.js";
import { IDragConstraint, IDragConstraintContext } from "./DragControlsConstraints.js";
import { Context } from "../engine/engine_setup.js";
import { type IGameObject } from "../engine/engine_types.js";
import { Behaviour, GameObject } from "./Component.js";
import { EventList } from "./EventList.js";
import type { IPointerEventHandler, PointerEventData } from "./ui/PointerEvents.js";
/**
 * The DragMode determines how an object is dragged around in the scene.
 */
export declare enum DragMode {
    /** Object stays at the same horizontal plane as it started. Commonly used for objects on the floor */
    XZPlane = 0,
    /** Object is dragged as if it was attached to the pointer. In 2D, that means it's dragged along the camera screen plane. In XR, it's dragged by the controller/hand. */
    Attached = 1,
    /** Object is dragged along the initial raycast hit normal. */
    HitNormal = 2,
    /** Combination of XZ and Screen based on the viewing angle. Low angles result in Screen dragging and higher angles in XZ dragging. */
    DynamicViewAngle = 3,
    /** The drag plane is snapped to surfaces in the scene while dragging. */
    SnapToSurfaces = 4,
    /** Don't allow dragging the object */
    None = 5
}
/**
 * Runtime view over the active drag settings for one input type (screen or XR).
 * `DragControls` constructs one instance per input type (`screenProfile` / `xrProfile`).
 * All properties are lazy getters over the flat serialized fields on the owning `DragControls`,
 * so runtime writes to those fields are reflected immediately without any extra bookkeeping.
 */
export declare class DragProfile {
    private readonly _dc;
    private readonly _xr;
    /** @internal — use {@link DragControls.screenProfile} or {@link DragControls.xrProfile} */
    constructor(_dc: DragControls, _xr: boolean);
    /** Active drag mode for this input type. */
    get dragMode(): DragMode;
    /** Whether the dragged object's rotation is frozen during drag. */
    get keepRotation(): boolean;
    /** Whether the dragged object's scale is frozen during two-pointer drag. */
    get keepScale(): boolean;
    /** Multiplier for push/pull distance in XR; always 1 for screen input. */
    get distanceDragFactor(): number;
}
/**
 * [DragControls](https://engine.needle.tools/docs/api/DragControls) enables interactive dragging of objects in 2D (screen space) or 3D (world space).
 *
 * ![](https://cloud.needle.tools/-/media/HyrtRDLjdmndr23_SR4mYw.gif)
 *
 * **Drag modes:**
 * - `XZPlane` - Drag on horizontal plane (good for floor objects)
 * - `Attached` - Follow pointer directly (screen plane in 2D, controller in XR)
 * - `HitNormal` - Drag along the surface normal where clicked
 * - `DynamicViewAngle` - Auto-switch between XZ and screen based on view angle
 * - `SnapToSurfaces` - Snap to scene geometry while dragging
 *
 * **Features:**
 * - Works across desktop, mobile, VR, and AR
 * - Optional grid snapping (`snapGridResolution`)
 * - Rotation preservation (`keepRotation`)
 * - Automatic networking with {@link SyncedTransform}
 *
 *
 * **Debug:** Use `?debugdrag` URL parameter for visual helpers.
 *
 * @example Basic draggable object
 * ```ts
 * const drag = myObject.addComponent(DragControls);
 * drag.dragMode = DragMode.XZPlane;
 * drag.snapGridResolution = 0.5; // Snap to 0.5 unit grid
 * ```
 *
 * - Example: https://engine.needle.tools/samples/collaborative-sandbox
 *
 * @summary Enables dragging of objects in 2D or 3D space
 * @category Interactivity
 * @group Components
 * @see {@link DragMode} for available drag behaviors
 * @see {@link Duplicatable} for drag-to-duplicate functionality
 * @see {@link SyncedTransform} for networked dragging
 * @see {@link ObjectRaycaster} for pointer detection
 */
export declare class DragControls extends Behaviour implements IPointerEventHandler {
    /**
     * Checks if any DragControls component is currently active with selected objects
     * @returns True if any DragControls component is currently active
     */
    static get HasAnySelected(): boolean;
    /** Tracks individual pointer spaces that are currently dragging, preventing counter desync on missed pointer-up events. */
    private static _activePointers;
    /**
     * Retrieves a list of all DragControl components that are currently dragging objects.
     * @returns Array of currently active DragControls components
     */
    static get CurrentlySelected(): DragControls[];
    /** Registry of currently active and enabled DragControls components */
    private static _instances;
    /**
     * Determines how and where the object is dragged along. Different modes include
     * dragging along a plane, attached to the pointer, or following surface normals.
     */
    dragMode: DragMode;
    /**
     * Snaps dragged objects to a 3D grid with the specified resolution.
     * Set to 0 to disable snapping.
     */
    snapGridResolution: number;
    /**
     * When true, maintains the original rotation of the dragged object while moving it.
     * When false, allows the object to rotate freely during dragging.
     */
    keepRotation: boolean;
    /**
     * When true, maintains the original scale of the dragged object while dragging it with two XR inputs.
     * When false, allows the object to scale freely during dragging with two XR inputs.
     */
    keepScale: boolean;
    /**
     * Determines how and where the object is dragged along while dragging in XR.
     * Uses a separate setting from regular drag mode for better XR interaction.
     */
    xrDragMode: DragMode;
    /**
     * When true, maintains the original rotation of the dragged object during XR dragging.
     * When false, allows the object to rotate freely during XR dragging.
     */
    xrKeepRotation: boolean;
    /**
     * When true, maintains the original scale of the dragged object while dragging it with two XR inputs.
     * When false, allows the object to scale freely during dragging with two XR inputs.
     */
    xrKeepScale: boolean;
    /**
     * Multiplier that affects how quickly objects move closer or further away when dragging in XR.
     * Higher values make distance changes more pronounced.
     * This is similar to mouse acceleration on a screen.
     */
    xrDistanceDragFactor: number;
    /**
     * When enabled, draws a visual line from the dragged object downwards to the next raycast hit,
     * providing visual feedback about the object's position relative to surfaces below it.
     */
    showGizmo: boolean;
    /** Drag profile for screen / touch / mouse input. Reads live from the flat serialized fields. */
    readonly screenProfile: DragProfile;
    /** Drag profile for XR tracked-pointer and transient-pointer input. Reads live from the flat `xr*` serialized fields. */
    readonly xrProfile: DragProfile;
    /** Invoked once when a drag begins (after the minimum drag distance threshold is met). */
    dragStarted: EventList;
    /** Invoked every frame while the object is being dragged. */
    dragUpdated: EventList;
    /** Invoked once when the last pointer is released and the drag ends. */
    dragEnded: EventList;
    /**
     * Returns the object currently being dragged by this DragControls component, if any.
     * @returns The object being dragged or null if no object is currently dragged
     */
    get draggedObject(): Object3D<import("three").Object3DEventMap> | null;
    /**
     * Updates the object that is being dragged by the DragControls.
     * This can be used to change the target during a drag operation.
     * @param obj The new object to drag, or null to stop dragging
     */
    setTargetObject(obj: Object3D | null): void;
    private _rigidbody;
    /** The object to be dragged – we pass this to handlers when they are created */
    private _targetObject;
    private static lastHovered;
    private _draggingRigidbodies;
    private _potentialDragStartEvt;
    private _dragHandlers;
    private _totalMovement;
    /** A marker is attached to components that are currently interacted with, to e.g. prevent them from being deleted. */
    private _marker;
    private _isDragging;
    private _didDrag;
    /** @internal */
    awake(): void;
    /** @internal */
    start(): void;
    /** @internal */
    onEnable(): void;
    /** @internal */
    onDisable(): void;
    onDestroy(): void;
    /**
     * Checks if editing is allowed for the current networking connection.
     * @param _obj Optional object to check edit permissions for
     * @returns True if editing is allowed
     */
    private allowEdit;
    /**
     * Handles pointer enter events. Sets the cursor style and tracks the hovered object.
     * @param evt Pointer event data containing information about the interaction
     * @internal
     */
    onPointerEnter?(evt: PointerEventData): void;
    /**
     * Handles pointer movement events. Marks the event as used if dragging is active.
     * @param args Pointer event data containing information about the movement
     * @internal
     */
    onPointerMove?(args: PointerEventData): void;
    /**
     * Handles pointer exit events. Resets the cursor style when the pointer leaves a draggable object.
     * @param evt Pointer event data containing information about the interaction
     * @internal
     */
    onPointerExit?(evt: PointerEventData): void;
    /**
     * Handles pointer down events. Initiates the potential drag operation if conditions are met.
     * @param args Pointer event data containing information about the interaction
     * @internal
     */
    onPointerDown(args: PointerEventData): void;
    /**
     * Handles pointer up events. Finalizes or cancels the drag operation.
     * @param args Pointer event data containing information about the interaction
     * @internal
     */
    onPointerUp(args: PointerEventData): void;
    /**
     * Updates the drag operation every frame. Processes pointer movement, accumulates drag distance
     * and triggers drag start once there's enough movement.
     * @internal
     */
    update(): void;
    /**
     * Called when the first pointer starts dragging on this object.
     * Sets up network synchronization and marks rigidbodies for dragging.
     * Not called for subsequent pointers on the same object.
     * @param evt Pointer event data that initiated the drag
     */
    private onFirstDragStart;
    /**
     * Called each frame as long as any pointer is dragging this object.
     * Keeps rigidbodies awake and fires the dragUpdated event.
     */
    private onAnyDragUpdate;
    /** Releases all active drag handlers and pointer tracking, then fires the drag-end lifecycle. */
    private _cancelDrag;
    /**
     * Called when the last pointer has been removed from this object.
     * Cleans up drag state and applies final velocities to rigidbodies.
     * @param evt Pointer event data for the last pointer that was lifted
     */
    private onLastDragEnd;
}
/**
 * Mutable context bag passed to an {@link IDragPlaneStrategy} on every frame update.
 * All object-typed properties are shared references — mutations made by the strategy
 * are immediately reflected in the owning {@link DragPointerHandler}.
 */
export interface IDragStrategyContext {
    readonly context: Context;
    /** The intermediate object whose position drives the dragged object. */
    readonly followObject: GameObject;
    /** Current dragged / target object. Refreshed before each strategy update call. */
    gameObject: Object3D | null;
    /** Accumulated world-space movement since drag start. */
    readonly totalMovement: Vector3;
    /** Local-space bounding box computed once at drag start. */
    readonly bounds: Box3;
    /** Active drag plane. Mutate in-place (e.g. setFromNormalAndCoplanarPoint). */
    readonly dragPlane: Plane;
    /** Drag-attachment hit point in the dragged object's local space. Mutate to reposition. */
    readonly hitPointInLocalSpace: Vector3;
    /** Surface normal at the drag-attachment point in the dragged object's local space. */
    readonly hitNormalInLocalSpace: Vector3;
    /** Realigns the drag plane to the current view direction. */
    setPlaneViewAligned(worldPoint: Vector3, useUpAngle: boolean): boolean;
}
/**
 * Extension point for per-mode drag plane setup and per-frame updates.
 * All built-in modes have a registered strategy in `_dragStrategyRegistry`.
 * {@link SnapToSurfacesDragStrategy} is the stateful reference implementation.
 */
export interface IDragPlaneStrategy {
    /**
     * Whether the handler should ray-cast into `dragPlane` to position the follow object.
     * Return `false` for modes (e.g. Attached) that move the follow object by another means.
     */
    readonly requiresPlaneIntersection: boolean;
    /**
     * Set the initial drag plane at drag start. Called once per drag.
     * @param context      Mutable handler state bag.
     * @param hitWP        World-space point where the pointer hit the object.
     * @param rayDirection World-space forward direction of the drag source.
     */
    initialize(context: IDragStrategyContext, hitWP: Vector3, rayDirection: Vector3): void;
    /** Reset all per-drag state. Called internally by initialize(). */
    reset(): void;
    /**
     * Update the drag plane for the current frame. Most modes are a no-op.
     * @returns `true` if a surface hit was found, `false` if not, `null` to abort
     *          the remainder of the frame's position update (drag hasn't started yet).
     */
    update(context: IDragStrategyContext, ray: Ray, dragSource: IGameObject, draggedObject: Object3D | null): boolean | null;
    /**
     * Optional: return the constraints this strategy needs injected into the pipeline.
     * Called once per drag in onDragStart (for single-pointer) and at multi-touch drag
     * start (for two-pointer). Each call must return **fresh** constraint instances so
     * callers do not share internal state.
     * @param cx  Snapshot of the dragged object and attachment point at drag start.
     */
    getConstraints?(cx: IDragConstraintContext): IDragConstraint[];
    /**
     * Optional: called by {@link MultiTouchDragHandler} every frame with the current
     * pinch/two-pointer scale ratio. Strategies that adjust constraints based on scale
     * (e.g. {@link XZPlaneDragStrategy} keeping the bounds bottom grounded) should
     * implement this. Pass `1` when `keepScale` is true so the correction is a no-op.
     */
    onTwoPointerScaleUpdate?(ratio: number): void;
}
