/**
 * @license
 * Copyright 2022-2025 Matter.js Authors
 * SPDX-License-Identifier: Apache-2.0
 */
import { Behavior } from "#behavior/Behavior.js";
import { ActionContext } from "#behavior/context/ActionContext.js";
import { Construction, Diagnostic, Environment, Immutable, MaybePromise, Observable } from "#general";
import { DataModelPath } from "#model";
import { Val } from "#protocol";
import { EndpointNumber } from "#types";
import { Agent } from "./Agent.js";
import { Behaviors } from "./properties/Behaviors.js";
import { Commands } from "./properties/Commands.js";
import { EndpointContainer } from "./properties/EndpointContainer.js";
import { EndpointLifecycle } from "./properties/EndpointLifecycle.js";
import { Parts } from "./properties/Parts.js";
import { SupportedBehaviors } from "./properties/SupportedBehaviors.js";
import { EndpointType } from "./type/EndpointType.js";
/**
 * Endpoints consist of a hierarchy of parts.  This class manages the current state of a single endpoint.
 *
 * You can interact with endpoints using an {@link Agent} created with {@link Endpoint.agentFor}.  Agents are stateless and
 * designed for quick instantiation so you can create them as needed then discard.
 *
 * Most often direct access to {@link Agent} is transparent as Matter.js acquires an agent as necessary for
 * {@link Behavior} interactions.
 */
export declare class Endpoint<T extends EndpointType = EndpointType.Empty> {
    #private;
    [Diagnostic.value]: unknown;
    /**
     * A string that uniquely identifies an endpoint.
     *
     * This ID must be unique amongst all Parts with the same owner.
     */
    get id(): string;
    /**
     * The endpoint ID or undefined if not yet assigned.
     */
    get maybeId(): string | undefined;
    /**
     * The Matter {@link EndpointNumber} of the endpoint.  This uniquely identifies the {@link Endpoint} in the scope of the
     * Matter node.
     */
    get number(): EndpointNumber;
    /**
     * The endpoint number or undefined if not yet assigned.
     */
    get maybeNumber(): EndpointNumber | undefined;
    /**
     * The owner of the endpoint.
     *
     * Every endpoint but the root endpoint (the "server node") is owned by another endpoint.
     */
    get owner(): Endpoint | undefined;
    /**
     * Access an {@link Agent} for this endpoint.
     *
     * An {@link Agent} allows you to interact directly with the behaviors supported by the endpoint.  Normally you
     * would use {@link act} to obtain an agent but {@link agentFor} is useful if you need to interact with multiple
     * endpoints in the same context.
     */
    agentFor<T extends EndpointType>(this: Endpoint<T>, context: ActionContext): Agent.Instance<T>;
    get endpointProtocol(): import("#protocol").EndpointProtocol | undefined;
    /**
     * Search for the owner of a specific type.
     *
     * Returns undefined if this owner is not found on the way up to the root endpoint.
     */
    ownerOfType<T extends EndpointType.Empty>(type: T): Endpoint<T> | undefined;
    /**
     * The endpoint's environment.  Endpoint implementations use the environment to access platform components such as
     * storage and network components.
     */
    get env(): Environment;
    /**
     * Access the pool of behaviors supported by this endpoint.
     */
    get behaviors(): Behaviors;
    /**
     * Current state values for all behaviors, keyed by behavior ID.  This view is read-only.
     */
    get state(): Immutable<SupportedBehaviors.StateOf<T["behaviors"]>>;
    /**
     * Current state for a specific behavior ID.
     *
     * Be aware that using a string type does not provide type checking and does not enforce the correctness of the used
     * Behavior type including all enabled features. Because of this the returned state is typed as a plain string
     * indexed record (Val.Struct). Please ensure to have proper checks in place when using this method with string type.
     */
    stateOf(type: string): Immutable<Val.Struct>;
    /**
     * Current state for a specific behavior.
     *
     * This is the recommended way to access state for a specific behavior because it provides proper type checking
     * and enforces the correctness of the used Behavior type including all enabled features.
     */
    stateOf<T extends Behavior.Type>(type: T): Immutable<Behavior.StateOf<T>>;
    /**
     * Version of {@link stateOf} that returns undefined instead of throwing if the requested behavior unsupported.
     */
    maybeStateOf(type: string): Immutable<Val.Struct> | undefined;
    /**
     * Version of {@link stateOf} that returns undefined instead of throwing if the requested behavior unsupported.
     */
    maybeStateOf<T extends Behavior.Type>(type: T): Immutable<Behavior.StateOf<T>> | undefined;
    /**
     * Update state values.  This is a patch operation; it only modifies properties in {@link values}.
     *
     * {@link values} is an object with a {@link Behavior.id} as the key and state values as sub-objects.
     *
     * Input values must adhere to the {@link Behavior.schema} of the target {@link Behavior}.  If not, set will throw
     * an error.
     *
     * This is a transactional operation.  An error results in no change.  The endpoint will wait for exclusive access
     * before applying changes.
     *
     * @param values the values to change
     */
    set(values: SupportedBehaviors.StatePatchOf<T["behaviors"]>): Promise<void>;
    /**
     * Update state values for a single behavior.
     *
     * The patch semantics used here are identical to {@link set}.
     *
     * This is the recommended way to set state for a single behavior because it provides proper type checking and
     * enforces the correctness of the used Behavior type including all enabled features.
     *
     * @param type the {@link Behavior} to patch
     * @param values the values to change
     */
    setStateOf<T extends Behavior.Type>(type: T, values: Behavior.PatchStateOf<T>): Promise<void>;
    /**
     * Update state values for a single behavior ID.
     *
     * The patch semantics used here are identical to {@link set}.
     *
     * Be aware that using a string type does not provide type checking and does not enforce the correctness of the used
     * Behavior type including all enabled features. Expect runtime errors if the provided values are not compatible
     * with the actual Behavior type.
     *
     * @param type the {@link Behavior} to patch
     * @param values the values to change
     */
    setStateOf(type: string, values: Val.Struct): Promise<void>;
    /**
     * Commands for all behaviors keyed by behavior ID.
     */
    get commands(): Commands<T>;
    /**
     * Commands for a specific behavior.
     */
    commandsOf<T extends Behavior.Type>(type: T): Commands.OfBehavior<T>;
    /**
     * Events for all behaviors keyed by behavior ID.
     */
    get events(): SupportedBehaviors.EventsOf<T["behaviors"]>;
    /**
     * Events for a specific behavior ID.
     *
     * Be aware that using a string type does not provide type checking and does not enforce the correctness of the used
     * Behavior type including all enabled features. Because of this each event is typed as Observable | undefined.
     * Please ensure to have proper checks in place when using this method with string type.
     */
    eventsOf(type: string): Immutable<Record<string, Observable | undefined>>;
    /**
     * Events for a specific behavior.
     *
     * This is the recommended way to access events for a specific behavior because it provides proper type checking
     * and enforces the correctness of the used Behavior type including all enabled features.
     */
    eventsOf<T extends Behavior.Type>(type: T | string): Behavior.EventsOf<T>;
    get construction(): Construction<Endpoint<T>>;
    /**
     * Create new endpoint.
     *
     * The endpoint will not initialize fully until added to a {@link Node}.  You can use {@link Endpoint.add} to
     * construct and initialize an {@link Endpoint} in one step.
     */
    constructor(config: Endpoint.Configuration<T> | T);
    /**
     * Create new endpoint.
     *
     * The endpoint will not initialize fully until added to a {@link Node}.  You can use {@link Endpoint.add} to
     * construct and initialize an {@link Endpoint} in one step.
     */
    constructor(type: T, options?: Endpoint.Options<T>);
    set id(id: string);
    protected get container(): undefined | EndpointContainer;
    set number(number: number);
    set owner(owner: Endpoint | undefined);
    /**
     * Add a child endpoint.  If this endpoint is initialized, awaits child initialization.
     *
     * If child initialization fails:
     *
     *   - If the child is essential (@see {@link EndpointLifecycle#isEssential}), removes the child and rethrows
     *
     *   - If the child is non-essential then logs the error but leaves the child installed.
     *
     * @param endpoint the {@link Endpoint} or {@link Endpoint.Configuration}
     */
    add<T extends EndpointType>(endpoint: Endpoint<T> | Endpoint.Configuration<T> | T): Promise<Endpoint<T>>;
    /**
     * Add a child endpoint with separate type and options arguments.
     *
     * @param type the {@link EndpointType} of the child endpoint
     * @param options settings for the new endpoint
     */
    add<T extends EndpointType>(type: T, options?: Endpoint.Options<T>): Promise<Endpoint<T>>;
    /**
     * The type of endpoint this endpoint implements.
     */
    get type(): EndpointType;
    /**
     * Access child parts.
     */
    get parts(): Parts;
    /**
     * Is this a parent Endpoint?
     */
    get hasParts(): boolean;
    /**
     * Endpoint information that varies as the endpoint initializes.
     */
    get lifecycle(): EndpointLifecycle;
    protected createLifecycle(isEssential?: boolean): EndpointLifecycle;
    /**
     * Create an {@link Agent.Type} for the endpoint.
     */
    get agentType(): Agent.Type<T>;
    /**
     * Execute a function against an {@link Agent} for the endpoint.
     *
     * Agents provide the highest-leve API for interacting with endpoints.  The agent is a composite object with
     * properties for each supported behavior.
     *
     * State changes made by {@link actor} are atomic and made permanent only when the actor exits unless you commit the
     * transaction manually.
     *
     * {@link actor} runs in an "offline" context where ACLs are ignored and all state is read/write.
     *
     * The {@link Agent} is destroyed after {@link actor} exits so you should not maintain references to the agent, its
     * behaviors or associated state.
     *
     * {@link actor} may be async.  If so, the acting context will remain open until the returned {@link Promise}
     * resolves.
     *
     * @param purpose textual description of operation used for diagnostics
     * @param actor the function that performs the action
     */
    act<R>(purpose: string, actor: (agent: Agent.Instance<T>) => MaybePromise<R>): MaybePromise<R>;
    /**
     * Version of {@link act} without explicit diagnostic purpose.
     */
    act<R>(actor: (agent: Agent.Instance<T>) => MaybePromise<R>): MaybePromise<R>;
    /**
     * Perform "soft" reset of the endpoint, reverting all in-memory structures to uninitialized.
     */
    reset(): Promise<void>;
    /**
     * Perform "hard" reset of the endpoint, reverting all in-memory and persistent state to uninitialized.
     */
    erase(): Promise<void>;
    /**
     * Erase all persisted data and destroy the endpoint.
     */
    delete(): Promise<void>;
    /**
     * Apply a depth-first visitor function to myself and all descendents.
     */
    visit<T extends void | PromiseLike<void>>(visitor: (endpoint: Endpoint) => T): T;
    close(): Promise<void>;
    [Construction.destruct](): Promise<void>;
    [Symbol.asyncDispose](): Promise<void>;
    toString(): string;
    /**
     * Path identifying the endpoint in the Matter data model.
     */
    get path(): DataModelPath;
    /**
     * Diagnostic identity.
     *
     * This is an unqualified path segment.
     */
    get identity(): string | EndpointNumber;
    /**
     * Asynchronous initialization.
     *
     * Derivatives may override to perform async construction prior to full initialization.
     */
    protected initialize(): MaybePromise;
    /**
     * Ensure requirements for construction are met.
     */
    protected assertConstructable(): void;
    /**
     * Complete initialization.  Invoked via {@link Construction#start} by the owner.
     */
    [Construction.construct](): MaybePromise;
    /**
     * Diagnostic information regarding endpoint state.
     */
    get diagnosticDict(): Record<string, unknown>;
}
export declare namespace Endpoint {
    type BehaviorOptions<T extends EndpointType = EndpointType.Empty, O extends EndpointOptions = EndpointOptions> = {
        -readonly [K in keyof T["behaviors"] as K extends keyof O ? never : K]?: Behavior.Options<T["behaviors"][K]>;
    };
    interface EndpointOptions {
        /**
         * The owner of the endpoint.
         *
         * If provided, takes ownership of the endpoint at construction.
         */
        owner?: Endpoint | Agent;
        /**
         * The endpoint's string identifier.  Must be unique within the parent.
         *
         * If you omit the identifier the node assigns a generated one for you.
         */
        id?: string;
        /**
         * The endpoint number.  Must be unique within the node.
         *
         * If you omit the endpoint number the node assigns a sequential one for you.
         */
        number?: number;
        /**
         * Child endpoints.
         *
         * This is the inverse of setting {@link owner} above.  The endpoint instantiates and takes ownership of child
         * endpoints at construction time.
         */
        parts?: Iterable<Endpoint.Definition>;
        /**
         * Designates whether an endpoint is essential.
         *
         * Endpoints are essential by default but you may disable by setting this to false.
         */
        isEssential?: boolean;
    }
    type Options<T extends EndpointType = EndpointType.Empty, O extends EndpointOptions = EndpointOptions> = BehaviorOptions<T, O> & O;
    type Configuration<T extends EndpointType = EndpointType.Empty, O extends EndpointOptions = EndpointOptions> = Options<T, O & {
        type: T;
    }> & {
        type: T;
    };
    /**
     * Definition of an endpoint.  May be an {@link EndpointType}, {@link Configuration}, or a {@link Endpoint}
     * instance.
     */
    type Definition<T extends EndpointType = EndpointType.Empty> = T | Configuration<T> | Endpoint<T>;
    /**
     * Obtain a configuration from constructor parameters.
     */
    function configurationFor<T extends EndpointType>(definition: T | Endpoint.Configuration<T>, options?: Endpoint.Options<T>): Configuration<T, EndpointOptions>;
    /**
     * Obtain an endpoint for the given {@link Definition}.
     */
    function partFor<T extends EndpointType>(definition: Definition<T>): Endpoint<T>;
}
//# sourceMappingURL=Endpoint.d.ts.map