/*!
 * 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 { ISnapshotTree } from "@fluidframework/driver-definitions/internal";
import { ISummaryTreeWithStats, ITelemetryContext, IGarbageCollectionData, AliasResult, IEnvelope, IFluidDataStoreChannel, IFluidDataStoreContext, IFluidDataStoreContextDetached, IFluidDataStoreFactory, IFluidDataStoreRegistry, IFluidParentContext, NamedFluidDataStoreRegistryEntries, IInboundSignalMessage, type IRuntimeMessageCollection } 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";
/**
 * True if a tombstoned object should be returned without erroring
 * @legacy
 * @alpha
 */
export declare const AllowTombstoneRequestHeaderKey = "allowTombstone";
/**
 * This version of the interface is private to this the package. It should never be exported under any tag.
 * It is used to manage interactions within the container-runtime package. If something is needed
 * cross package, it is likely it is also being used cross layer (ContainerRuntime * DataStoreRuntime).
 * If that is the case, the change likely needs to be staged directly on IFluidParentContext. Changes
 * being staged on IFluidParentContext can be added here as well, likely with optionality removed,
 * to ease interactions within this package.
 */
export interface IFluidParentContextPrivate extends Omit<IFluidParentContext, "isReadOnly"> {
    readonly isReadOnly: () => boolean;
}
/**
 * Creates a shallow wrapper of {@link IFluidParentContext}. The wrapper can then have its methods overwritten as needed
 */
export declare function wrapContext(context: IFluidParentContextPrivate): IFluidParentContextPrivate;
/**
 * Returns the type of the given local data store from its package path.
 */
export declare function getLocalDataStoreType(localDataStore: LocalFluidDataStoreContext): string;
/**
 * 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: IFluidParentContextPrivate;
    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 readonly pendingAliasMap;
    protected readonly contexts: DataStoreContexts;
    private readonly aliasedDataStores;
    constructor(baseSnapshot: ISnapshotTree | ISnapshot | undefined, parentContext: IFluidParentContextPrivate, 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): IFluidParentContextPrivate;
    /**
     * 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 processAttachMessages;
    private processAliasMessages;
    processAliasMessageCore(internalId: string, alias: string, messageTimestampMs?: number): 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[]>, loadingGroupId?: string): IFluidDataStoreContextInternal;
    protected createContext<T extends LocalFluidDataStoreContext>(id: string, pkg: Readonly<string[]>, contextCtor: new (props: ILocalDetachedFluidDataStoreContextProps) => T, loadingGroupId?: string): T;
    get disposed(): boolean;
    dispose(): void;
    reSubmit(type: string, content: unknown, localOpMetadata: unknown, squash: boolean): void;
    protected reSubmitChannelOp(type: string, content: unknown, localOpMetadata: unknown, squash: boolean): void;
    rollback(type: string, content: unknown, localOpMetadata: unknown): void;
    applyStashedOp(content: unknown): Promise<unknown>;
    protected applyStashedChannelChannelOp(envelope: IEnvelope): Promise<unknown>;
    private applyStashedAttachOp;
    /**
     * Process messages for this channel collection. The messages here are contiguous messages in a batch.
     * @param messageCollection - The collection of messages to process.
     */
    processMessages(messageCollection: IRuntimeMessageCollection): void;
    /**
     * Process channel messages. The messages here are contiguous channel type messages in a batch. Bunch
     * of contiguous messages for a data store should be sent to it together.
     * @param messageCollection - The collection of messages to process.
     */
    private processChannelMessages;
    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(canSendOps: boolean, clientId?: string): void;
    /**
     * Enumerates the contexts and calls notifyReadOnlyState on them.
     */
    notifyReadOnlyState(readonly: boolean): void;
    /**
     * Notifies all data store contexts about the current staging mode state.
     *
     * @param staging - A boolean indicating whether the container is in staging mode.
     */
    notifyStagingMode(staging: boolean): void;
    setAttachState(attachState: AttachState.Attaching | AttachState.Attached): void;
    get size(): number;
    /**
     * Create a summary. Used when attaching or serializing a detached container.
     */
    getAttachSummary(telemetryContext?: ITelemetryContext): ISummaryTreeWithStats;
    /**
     * Gets the GC data. Used when attaching or serializing a detached container.
     */
    getAttachGCData(telemetryContext?: ITelemetryContext): IGarbageCollectionData;
    /**
     * Helper method for preparing to attach this channel.
     * Runs the callback for each bound context to incorporate its data however the caller specifies
     */
    private visitLocalBoundContextsDuringAttach;
    /**
     * Helper method for preparing to summarize this channel.
     * Runs the callback for each bound context to incorporate its data however the caller specifies
     */
    private visitContextsDuringSummary;
    summarize(fullTree: boolean, trackState: boolean, telemetryContext?: ITelemetryContext): Promise<ISummaryTreeWithStats>;
    /**
     * 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 implements IFluidDataStoreFactory {
    private readonly provideEntryPoint;
    readonly type = "ChannelCollectionChannel";
    IFluidDataStoreRegistry: IFluidDataStoreRegistry;
    constructor(registryEntries: NamedFluidDataStoreRegistryEntries, provideEntryPoint: (runtime: IFluidDataStoreChannel) => Promise<FluidObject>);
    get IFluidDataStoreFactory(): ChannelCollectionFactory;
    instantiateDataStore(context: IFluidDataStoreContext, _existing: boolean): Promise<IFluidDataStoreChannel>;
}
//# sourceMappingURL=channelCollection.d.ts.map