/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { AttachState } from "@fluidframework/container-definitions";
import { FluidObject, IDisposable, IRequest, IResponse, ITelemetryBaseLogger } from "@fluidframework/core-interfaces";
import type { IFluidHandleInternal } from "@fluidframework/core-interfaces/internal";
import type { ISnapshot } from "@fluidframework/driver-definitions/internal";
import { ISequencedDocumentMessage, ISnapshotTree } from "@fluidframework/protocol-definitions";
import { IInboundSignalMessage } from "@fluidframework/runtime-definitions";
import { ISummaryTreeWithStats, ITelemetryContext, IGarbageCollectionData, AliasResult, IEnvelope, IFluidDataStoreChannel, IFluidDataStoreContext, IFluidDataStoreContextDetached, IFluidDataStoreFactory, IFluidDataStoreRegistry, IFluidParentContext, NamedFluidDataStoreRegistryEntries } from "@fluidframework/runtime-definitions/internal";
import { MonitoringContext } from "@fluidframework/telemetry-utils/internal";
import { RuntimeHeaderData } from "./containerRuntime.js";
import { IFluidDataStoreContextInternal, ILocalDetachedFluidDataStoreContextProps, LocalFluidDataStoreContext } from "./dataStoreContext.js";
import { DataStoreContexts } from "./dataStoreContexts.js";
import { GCNodeType, IGCNodeUpdatedProps } from "./gc/index.js";
import { IContainerRuntimeMetadata } from "./summary/index.js";
/**
 * Accepted header keys for requests coming to the runtime.
 * @internal
 */
export declare enum RuntimeHeaders {
    /** True to wait for a data store to be created and loaded before returning it. */
    wait = "wait",
    /** True if the request is coming from an IFluidHandle. */
    viaHandle = "viaHandle"
}
/** True if a tombstoned object should be returned without erroring
 * @alpha
 */
export declare const AllowTombstoneRequestHeaderKey = "allowTombstone";
/**
 * [IRRELEVANT IF throwOnInactiveLoad OPTION NOT SET] True if an inactive object should be returned without erroring
 * @internal
 */
export declare const AllowInactiveRequestHeaderKey = "allowInactive";
/**
 * Creates a shallow wrapper of {@link IFluidParentContext}. The wrapper can then have its methods overwritten as needed
 */
export declare function wrapContext(context: IFluidParentContext): IFluidParentContext;
/**
 * Creates a wrapper of a {@link IFluidParentContext} to be provided to the inner datastore channels.
 * The wrapper will have the submit methods overwritten with the appropriate id as the destination address.
 *
 * @param id - the id of the channel
 * @param parentContext - the {@link IFluidParentContext} to wrap
 * @returns A wrapped {@link IFluidParentContext}
 */
export declare function wrapContextForInnerChannel(id: string, parentContext: IFluidParentContext): IFluidParentContext;
/**
 * This class encapsulates data store handling. Currently it is only used by the container runtime,
 * but eventually could be hosted on any channel once we formalize the channel api boundary.
 * @internal
 */
export declare class ChannelCollection implements IFluidDataStoreChannel, IDisposable {
    protected readonly baseSnapshot: ISnapshotTree | ISnapshot | undefined;
    readonly parentContext: IFluidParentContext;
    private readonly gcNodeUpdated;
    private readonly isDataStoreDeleted;
    private readonly aliasMap;
    private readonly pendingAttach;
    readonly attachOpFiredForDataStore: Set<string>;
    protected readonly mc: MonitoringContext;
    private readonly disposeOnce;
    readonly entryPoint: IFluidHandleInternal<FluidObject>;
    readonly containerLoadStats: {
        readonly containerLoadDataStoreCount: number;
        readonly referencedDataStoreCount: number;
    };
    private dataStoresSinceLastGC;
    private readonly containerRuntimeHandle;
    private readonly pendingAliasMap;
    protected readonly contexts: DataStoreContexts;
    private readonly aliasedDataStores;
    constructor(baseSnapshot: ISnapshotTree | ISnapshot | undefined, parentContext: IFluidParentContext, baseLogger: ITelemetryBaseLogger, gcNodeUpdated: (props: IGCNodeUpdatedProps) => void, isDataStoreDeleted: (nodePath: string) => boolean, aliasMap: Map<string, string>, provideEntryPoint: (runtime: ChannelCollection) => Promise<FluidObject>);
    get aliases(): ReadonlyMap<string, string>;
    get pendingAliases(): Map<string, Promise<AliasResult>>;
    waitIfPendingAlias(maybeAlias: string): Promise<AliasResult>;
    /** For sampling. Only log once per container */
    private shouldSendAttachLog;
    protected wrapContextForInnerChannel(id: string): IFluidParentContext;
    /**
     * IFluidDataStoreChannel.makeVisibleAndAttachGraph implementation
     * Not clear when it would be called and what it should do.
     * Currently this API is called by context only for root data stores.
     */
    makeVisibleAndAttachGraph(): void;
    private processAttachMessage;
    private processAliasMessage;
    processAliasMessageCore(internalId: string, alias: string): boolean;
    private alreadyProcessed;
    /** Package up the context's attach summary etc into an IAttachMessage */
    private generateAttachMessage;
    /**
     * Make the data store locally visible in the container graph by moving the data store context from unbound to
     * bound list and submitting the attach message. This data store can now be reached from the root.
     * @param id - The id of the data store context to make visible.
     */
    private makeDataStoreLocallyVisible;
    protected submitAttachChannelOp(localContext: LocalFluidDataStoreContext): void;
    /**
     * Generate compact internal DataStore ID.
     *
     * A note about namespace and name collisions:
     * This code assumes that that's the only way to generate internal IDs, and that it's Ok for this namespace to overlap with
     * user-provided alias names namespace.
     * There are two scenarios where it could cause trouble:
     * 1) Old files, where (already removed) CreateRoot*DataStore*() API was used, and thus internal name of data store
     * was provided by user. Such files may experience name collision with future data stores that receive a name generated
     * by this function.
     * 2) Much less likely, but if it happen that internal ID (generated by this function) is exactly the same as alias name
     * that user might use in the future, them ContainerRuntime.getAliasedDataStoreEntryPoint() or
     * ContainerRuntime.getDataStoreFromRequest() could return a data store with internalID matching user request, even though
     * user expected some other data store (that would receive alias later).
     * Please note that above mentioned functions have the implementation they have (allowing #2) due to #1.
     */
    protected createDataStoreId(): string;
    createDetachedDataStore(pkg: Readonly<string[]>, loadingGroupId?: string): IFluidDataStoreContextDetached;
    createDataStoreContext(pkg: Readonly<string[]>, props?: any, loadingGroupId?: string): IFluidDataStoreContextInternal;
    protected createContext<T extends LocalFluidDataStoreContext>(id: string, pkg: Readonly<string[]>, contextCtor: new (props: ILocalDetachedFluidDataStoreContextProps) => T, createProps?: any, loadingGroupId?: string): T;
    get disposed(): boolean;
    readonly dispose: () => void;
    reSubmit(type: string, content: any, localOpMetadata: unknown): void;
    protected reSubmitChannelOp(type: string, content: any, localOpMetadata: unknown): void;
    rollback(type: string, content: any, localOpMetadata: unknown): void;
    applyStashedOp(content: unknown): Promise<unknown>;
    protected applyStashedChannelChannelOp(envelope: IEnvelope): Promise<unknown>;
    private applyStashedAttachOp;
    process(message: ISequencedDocumentMessage, local: boolean, localMessageMetadata: unknown, addedOutboundReference?: (fromNodePath: string, toNodePath: string) => void): void;
    protected processChannelOp(address: string, message: ISequencedDocumentMessage, local: boolean, localMessageMetadata: unknown): void;
    private getDataStore;
    /**
     * Returns the data store requested with the given id if available. Otherwise, returns undefined.
     */
    getDataStoreIfAvailable(id: string, requestHeaderData: RuntimeHeaderData): Promise<IFluidDataStoreContextInternal | undefined>;
    /**
     * Checks if the data store has been deleted by GC. If so, log an error.
     * @param id - The data store's id.
     * @param context - The data store context.
     * @param deletedLogSuffix - Whether it was Changed or Requested (will go into the eventName)
     * @param callSite - The function name this is called from.
     * @param requestHeaderData - The request header information to log if the data store is deleted.
     * @param originalRequest - The original request (could be for a child of the DataStore)
     * @returns true if the data store is deleted. Otherwise, returns false.
     */
    private checkAndLogIfDeleted;
    processSignal(messageArg: IInboundSignalMessage, local: boolean): void;
    setConnectionState(connected: boolean, clientId?: string): void;
    setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void;
    get size(): number;
    summarize(fullTree: boolean, trackState: boolean, telemetryContext?: ITelemetryContext): Promise<ISummaryTreeWithStats>;
    /**
     * Create a summary. Used when attaching or serializing a detached container.
     */
    getAttachSummary(telemetryContext?: ITelemetryContext): ISummaryTreeWithStats;
    /**
     * Before GC runs, called by the garbage collector to update any pending GC state.
     * The garbage collector needs to know all outbound references that are added. Since root data stores are not
     * explicitly marked as referenced, notify GC of new root data stores that were added since the last GC run.
     */
    updateStateBeforeGC(): Promise<void>;
    /**
     * Generates data used for garbage collection. It does the following:
     *
     * 1. Calls into each child data store context to get its GC data.
     *
     * 2. Prefixes the child context's id to the GC nodes in the child's GC data. This makes sure that the node can be
     * identified as belonging to the child.
     *
     * 3. Adds a GC node for this channel to the nodes received from the children. All these nodes together represent
     * the GC data of this channel.
     *
     * @param fullGC - true to bypass optimizations and force full generation of GC data.
     */
    getGCData(fullGC?: boolean): Promise<IGarbageCollectionData>;
    /**
     * After GC has run, called to notify this Container's data stores of routes that are used in it.
     * @param usedRoutes - The routes that are used in all data stores in this Container.
     */
    updateUsedRoutes(usedRoutes: readonly string[]): void;
    deleteChild(dataStoreId: string): void;
    /**
     * Delete data stores and its objects that are sweep ready.
     * @param sweepReadyDataStoreRoutes - The routes of data stores and its objects that are sweep ready and should
     * be deleted.
     * @returns The routes of data stores and its objects that were deleted.
     */
    deleteSweepReadyNodes(sweepReadyDataStoreRoutes: readonly string[]): readonly string[];
    /**
     * This is called to update objects whose routes are tombstones.
     *
     * A Tombstoned object has been unreferenced long enough that GC knows it won't be referenced again.
     * Tombstoned objects are eventually deleted by GC.
     *
     * @param tombstonedRoutes - The routes that are tombstones in all data stores in this Container.
     */
    updateTombstonedRoutes(tombstonedRoutes: readonly string[]): void;
    /**
     * Returns the outbound routes of this channel. Only root data stores are considered referenced and their paths are
     * part of outbound routes.
     */
    private getOutboundRoutes;
    /**
     * Called by GC to retrieve the package path of a data store node with the given path.
     */
    getDataStorePackagePath(nodePath: string): Promise<readonly string[] | undefined>;
    /**
     * Called by GC to determine if a node is for a data store or for an object within a data store (for e.g. DDS).
     * @returns the GC node type if the node belongs to a data store or object within data store, undefined otherwise.
     */
    getGCNodeType(nodePath: string): GCNodeType | undefined;
    internalId(maybeAlias: string): string;
    request(request: IRequest): Promise<IResponse>;
}
export declare function getSummaryForDatastores(snapshot: ISnapshotTree | undefined, metadata?: IContainerRuntimeMetadata): ISnapshotTree | undefined;
/**
 * Traverse this op's contents and detect any outbound routes that were added by this op.
 *
 * @internal
 */
export declare function detectOutboundReferences(address: string, contents: unknown, addedOutboundReference: (fromNodePath: string, toNodePath: string) => void): void;
/** @internal */
export declare class ChannelCollectionFactory<T extends ChannelCollection = ChannelCollection> implements IFluidDataStoreFactory {
    private readonly provideEntryPoint;
    private readonly ctor;
    readonly type = "ChannelCollectionChannel";
    IFluidDataStoreRegistry: IFluidDataStoreRegistry;
    constructor(registryEntries: NamedFluidDataStoreRegistryEntries, provideEntryPoint: (runtime: IFluidDataStoreChannel) => Promise<FluidObject>, ctor: (...args: ConstructorParameters<typeof ChannelCollection>) => T);
    get IFluidDataStoreFactory(): this;
    instantiateDataStore(context: IFluidDataStoreContext, _existing: boolean): Promise<IFluidDataStoreChannel>;
}
//# sourceMappingURL=channelCollection.d.ts.map