import { Credentials, InvokeResponse } from '@microsoft/teams.api';
import { Client as HttpClient, IEventEmitter, ILogger } from '@microsoft/teams.common';
import { IActivityEvent } from '../events';
import { HttpMethod, HttpRouteHandler, IHttpServerAdapter } from '../http/adapter';
import { IAppTokenProvider } from '../token-provider';
import { SocketReadyFrame, SocketModeOptions, SocketModeStatus } from './types';
/**
 * Lifecycle events emitted by {@link SocketModeAdapter.events}. Subscribe via
 * `app.socketMode?.events.on('ready', ...)` to observe the socket lifecycle.
 * Each payload carries the `geo` it relates to, since a bot maintains one
 * connection per geo.
 *
 * @experimental This API is in preview and may change in the future.
 */
export type SocketModeEvents = {
    /** A geo's socket connected and Teams backend service confirmed readiness. */
    ready: {
        geo: string;
        frame: SocketReadyFrame;
    };
    /**
     * A geo's socket dropped unexpectedly; a reconnect for that geo may be in
     * progress. Not emitted for a successful planned proactive token rotation,
     * which renegotiates transparently without surfacing a drop. When a
     * reconnect or planned rotation is rejected with HTTP 401/403, this is
     * emitted with `terminal: true` and that {@link NegotiateError}, and the geo
     * stops reconnecting — so after a network drop, listeners see one event for
     * the drop and a second for the auth rejection.
     */
    disconnected: {
        geo: string;
        error?: Error;
        /**
         * `true` when this geo has stopped for good and will not reconnect until the
         * app is restarted (negotiate was rejected with HTTP 401/403). `false` for
         * an ordinary drop, after which the SDK keeps reconnecting.
         */
        terminal: boolean;
    };
    /**
     * A geo's socket reconnected after an unexpected drop and re-established its
     * Teams backend service group. Not emitted for a planned token rotation.
     */
    reconnected: {
        geo: string;
    };
};
/**
 * Dependencies the owning {@link App} supplies to the socket adapter, wired
 * internally rather than by the developer.
 */
export type SocketModeAdapterDeps = {
    /** App credentials used to identify the bot on reply frames. */
    readonly credentials?: Credentials;
    /** The app's shared HTTP client used for Socket Mode negotiation. */
    readonly client: HttpClient;
    /**
     * Token source for the Bot Framework token that authenticates the Teams backend service
     * negotiate call, reusing the app's credentials.
     */
    readonly tokenProvider: IAppTokenProvider;
    /**
     * Dispatches a connection-authenticated activity into the owning app's shared
     * activity pipeline. Socket Mode creates the normalized token internally.
     */
    readonly processActivity: (event: IActivityEvent) => Promise<InvokeResponse>;
    /**
     * The messaging endpoint path the owning {@link HttpServer} registers its
     * inbound-activity route on. Inbound socket frames are dispatched to the
     * handler registered for this path; {@link SocketModeAdapter.registerRoute}
     * calls for any other path (e.g. `app.function()` routes) are no-ops, since a
     * socket transport serves only messaging.
     */
    readonly messagingEndpoint: string;
    /**
     * Surface an unexpected inbound-processing error to the app pipeline. May be
     * async — the transport awaits it (behind an error boundary) so an
     * `App.onError` that performs async work (logging, telemetry flush) completes
     * before the reply frame is returned.
     */
    readonly onError?: (error: Error) => void | Promise<void>;
    /** Logger to use; defaults to a `SocketModeAdapter`-tagged console logger. */
    readonly logger?: ILogger;
};
/**
 * Inbound Socket Mode transport, implemented as an {@link IHttpServerAdapter}.
 *
 * With `new App({ socketMode: true })` the app receives activities over a
 * Teams backend service-negotiated Azure SignalR socket. Rather than being a
 * separate server, Socket Mode plugs in as the adapter *inside* the app's single
 * {@link HttpServer}. Inbound frames enter the same app activity pipeline as
 * HTTP after the connection-authenticated transport creates their normalized
 * token. Only inbound delivery moves to the socket; outbound sends stay on HTTP
 * and handlers stay transport-agnostic.
 *
 * No inbound HTTP adapter, listener, route, or public endpoint is started. The
 * socket is authenticated once at negotiate, so the adapter synthesizes the
 * {@link IToken} the pipeline expects without exposing transport trust through
 * the public HTTP request interface. Invoke activities return a real invoke
 * response over SignalR client results; one-way activities return a post-handler
 * ack. Not usable until Teams backend service's `SocketReady` frame arrives.
 *
 * Browser-oriented calls are no-ops: tabs, remote functions, OAuth callbacks,
 * and other non-messaging routes require an HTTP transport.
 * WebSocket is only recommended for use when developing agents.
 *
 * @experimental This API is in preview and may change in the future.
 */
export declare class SocketModeAdapter implements IHttpServerAdapter {
    readonly options: SocketModeOptions;
    private readonly deps;
    /**
     * Lifecycle event surface for observing the socket without reaching into the
     * transport. Emits `ready`, `disconnected`, and `reconnected`.
     */
    readonly events: IEventEmitter<SocketModeEvents>;
    private readonly log;
    private _lifecycle;
    private readonly transportSettings;
    /** One independent supervised connection per geo. */
    private geoSockets;
    /** Aborts all in-flight negotiate/connect/back-off waits when stopping. */
    private abort?;
    private stopped;
    constructor(options: SocketModeOptions | undefined, deps: SocketModeAdapterDeps);
    /**
     * Aggregate lifecycle status across all geo connections. `ready` means every
     * geo is ready; `connecting` while any geo is still (re)connecting and none is
     * mid-drop; `disconnected` when at least one geo has dropped and is recovering,
     * or has stopped reconnecting after a 401/403 negotiate rejection.
     */
    get status(): SocketModeStatus;
    /** Per-geo status snapshot, for diagnostics/observability. */
    get geoStatuses(): ReadonlyArray<{
        geo: string;
        status: SocketModeStatus;
    }>;
    /** The geos this server connects to (resolved from options/defaults). */
    get geoList(): readonly string[];
    /**
     * {@link IHttpServerAdapter} route registration. The owning {@link HttpServer}
     * registers its inbound-activity route here as part of normal server
     * initialization. Socket Mode dispatches through its internal app callback, so
     * the messaging route is accepted as a no-op. Any other path (e.g.
     * `app.function()` POST routes) is also a no-op, but is warned because the
     * corresponding HTTP-only feature is unavailable.
     */
    registerRoute(method: HttpMethod, path: string, _handler: HttpRouteHandler): void;
    /**
     * {@link IHttpServerAdapter} static-file serving. No-op for Socket Mode — tabs
     * and other static assets require an HTTP transport, so the ignored mount is
     * warned.
     */
    serveStatic(path: string, _directory: string): void;
    /**
     * {@link IHttpServerAdapter} lifecycle: open one socket per geo, resolving only
     * once every geo's readiness contract is satisfied. Called by {@link App.start}
     * via {@link HttpServer.start}. The `port` argument is unused — Socket Mode
     * dials out rather than listening.
     *
     * The initial connect for each geo is retried for up to 30 seconds before
     * `App.start()` rejects; once all geos are ready, each geo's supervisor keeps
     * it alive across drops and token expiry independently until {@link stop}.
     */
    start(_port?: number | string): Promise<void>;
    /**
     * {@link IHttpServerAdapter} lifecycle: stop admitting activities, abort any
     * reconnect/back-off in progress, then close every geo's socket. In-flight
     * handlers are not awaited: any activity whose reply doesn't make it out before
     * shutdown is redelivered by the Teams backend to another connection/instance.
     */
    stop(): Promise<void>;
    /** Build one geo supervisor from the adapter's narrow internal callbacks. */
    private createGeoSocket;
    /** Build a connection for a geo. */
    private createConnection;
    /** Back-off delay (ms) for a reconnect attempt (shared policy across geos). */
    private backoffDelay;
    /** Abortable delay; resolves `true` when it completed, `false` if aborted. */
    private sleep;
    private retryAfterOf;
    /** Emit a lifecycle event without letting a throwing listener break state. */
    private emit;
    /**
     * Dispatch one inbound envelope after the geo supervisor applies its
     * generation/readiness/admission fence. There is no concurrency cap or
     * admission queue: SignalR already invokes the handler per activity, the Teams
     * backend load-balances delivery across connections/instances, and each
     * activity carries a reply deadline, so an in-SDK cap would mostly produce
     * work whose reply is discarded.
     */
    private dispatch;
    /** The configured geos, defaulting to amer/emea/apac. */
    private resolveGeos;
    /**
     * Handle one inbound envelope: feed the embedded activity and an internally
     * synthesized token into the app pipeline, then return the reply frame to send
     * back over client results.
     *
     * Invoke activities return the pipeline's status/body; one-way activities
     * return a post-handler acknowledgement once the pipeline has run.
     */
    private handleEnvelope;
    /**
     * Invoke the optional {@link SocketModeAdapterDeps.onError} hook, awaiting it
     * (behind an error boundary) so an async handler completes before we return
     * the reply frame, and a throwing/rejecting hook can't crash the transport.
     */
    private reportError;
    /** The bot's client id, echoed on reply frames for Teams backend service routing. */
    private get botId();
    /**
     * Acquire the Bot Framework negotiate token (string form) via the app's token
     * provider, so Socket Mode reuses the same credential flow as the rest of the SDK.
     */
    private acquireBotToken;
    /**
     * Build the normalized token expected by the shared activity pipeline. Socket
     * authentication is established at negotiation, so there is no per-activity
     * bearer token to validate or forward.
     */
    private inboundToken;
}
