import { EventEmitter } from "eventemitter3";
import type * as THREE from "three";
import { CoreContext, ModulesRecord } from "./CoreContext";
import { Evnt } from "./Events";
import { Object3DFeature } from "./Object3DFeature";
export type Object3DFeaturabilityEventTypes<TModules extends ModulesRecord = {}> = {
    [Evnt.AttCtx]: [ctx: CoreContext<TModules>];
    [Evnt.DetCtx]: [ctx: CoreContext<TModules>];
    [Evnt.FtAdd]: [feature: Object3DFeature<TModules>];
    [Evnt.FtRem]: [feature: Object3DFeature<TModules>];
};
declare const key = "__kvy_ftblty__";
export declare class Object3DFeaturability<TModules extends ModulesRecord = {}, TObj extends THREE.Object3D = THREE.Object3D> extends EventEmitter<Object3DFeaturabilityEventTypes<TModules>> {
    /**
     * Extracts {@link Object3DFeaturability} from the given object if it is featurable.
     *
     * @param obj - The object to extract {@link Object3DFeaturability} from.
     * @returns The {@link Object3DFeaturability} instance if available, otherwise `null`.
     */
    static extract<TModules extends ModulesRecord = {}, TObj extends THREE.Object3D = THREE.Object3D>(obj: TObj): Object3DFeaturability<TModules, TObj> | null;
    /**
     * Creates or retrieves {@link Object3DFeaturability} for the given object.
     * If the object already has featurability, it is returned. Otherwise, a new instance is created.
     *
     * @param obj - The object to make featurable.
     * @returns The {@link Object3DFeaturability} instance for the object.
     */
    static from<TModules extends ModulesRecord = {}, TObj extends THREE.Object3D = THREE.Object3D>(obj: TObj): Object3DFeaturability<TModules, TObj>;
    static destroy<TObj extends THREE.Object3D = THREE.Object3D>(obj: TObj, force?: boolean): void;
    static log: (target: Object3DFeaturability, msg: string) => void;
    readonly isObjectFeaturability = true;
    readonly object: IFeaturablePrivate<TModules, TObj>;
    get ctx(): CoreContext<TModules> | null;
    get features(): Object3DFeature<any, string | symbol>[];
    private _ctx;
    private readonly _features;
    private constructor();
    /**
     * Destroys the featurability instance and removes all features.
     */
    destroy(force?: boolean): void;
    destroyAllFeatures(): void;
    /**
     * Adds a new feature to the object.
     * @param Feature The feature class.
     * @param props The properties required for initialization.
     * @param beforeAttach A callback invoked before attaching the feature.
     * @returns The created feature instance.
     */
    addFeature<TFeature extends Object3DFeature<any, any>, TProps>(Feature: new (object: IFeaturable, props: TProps) => TFeature, props: keyof TProps extends never ? undefined : TProps, beforeAttach?: (feature: TFeature) => void): TFeature;
    addFeature<TFeature extends Object3DFeature<any, any>>(Feature: new (object: IFeaturable) => TFeature): TFeature;
    /**
     * Retrieves a feature of a specific class, if present.
     * @param FeatureClass The feature class to search for.
     * @returns The feature instance, or `null` if not found.
     */
    getFeature<TFeatureClass extends typeof Object3DFeature>(FeatureClass: TFeatureClass): InstanceType<TFeatureClass> | null;
    /**
     * Retrieves a feature of a specific class, if present.
     * @param FeatureClass The feature class to search for.
     * @returns The feature instance, or `null` if not found.
     */
    getFeatureBy<TFeature extends Object3DFeature = Object3DFeature>(predicate: (feature: TFeature) => boolean): TFeature | null;
    /**
     * Removes a feature from the object and destroys it.
     * @param feature The feature instance to remove.
     */
    destroyFeature<TFeature extends Object3DFeature<any, any>>(feature: TFeature): boolean;
    /**
     * Attaches or detaches the object from a `CoreContext`.
     * @warning You should be careful to use this method manually
     * @param ctx The `CoreContext` instance, or `null` to detach.
     * @returns This instance.
     * @warning Use with caution.
     */
    setCtx(ctx: CoreContext<TModules> | null): this;
    private onObjectAdded;
    private inheritCtx;
    private onObjectRemoved;
    private attachCtx;
    private detachCtx;
    private propagateAttachCtxDown;
    private propagateDetachCtxDown;
    private _log;
}
export type IFeaturable<TModules extends ModulesRecord = any, TObj extends THREE.Object3D = THREE.Object3D> = TObj & {
    isFeaturable: true;
};
type IFeaturablePrivate<TModules extends ModulesRecord = any, TObj extends THREE.Object3D = THREE.Object3D> = TObj & {
    [key]?: Object3DFeaturability<TModules, TObj>;
    isFeaturable?: true;
};
export {};
