/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { AttachState, } from "@fluidframework/container-definitions/internal";
import { assert } from "@fluidframework/core-utils/internal";
import { readAndParse } from "@fluidframework/driver-utils/internal";
import { SummaryTreeBuilder } from "@fluidframework/runtime-utils/internal";
export const redirectTableBlobName = ".redirectTable";
/**
 * @internal
 */
export const blobsTreeName = ".blobs";
/**
 * Reads blobs needed to load BlobManager from storage.
 *
 */
export const loadBlobManagerLoadInfo = async (context) => loadV1(context);
const loadV1 = async (context) => {
    const blobsTree = context.baseSnapshot?.trees[blobsTreeName];
    if (!blobsTree) {
        return {};
    }
    let redirectTableEntries = [];
    const tableId = blobsTree.blobs[redirectTableBlobName];
    if (tableId) {
        redirectTableEntries = await readAndParse(context.storage, tableId);
    }
    const ids = Object.entries(blobsTree.blobs)
        .filter(([k, _]) => k !== redirectTableBlobName)
        .map(([_, v]) => v);
    return { ids, redirectTable: redirectTableEntries };
};
export const toRedirectTable = (blobManagerLoadInfo, logger, attachState) => {
    logger.sendTelemetryEvent({
        eventName: "AttachmentBlobsLoaded",
        count: blobManagerLoadInfo.ids?.length ?? 0,
        redirectTable: blobManagerLoadInfo.redirectTable?.length,
    });
    const redirectTable = new Map(blobManagerLoadInfo.redirectTable);
    const detached = attachState !== AttachState.Attached;
    if (blobManagerLoadInfo.ids) {
        // If we are detached, we don't have storage IDs yet, so set to undefined
        // Otherwise, set identity (id -> id) entries.
        for (const entry of blobManagerLoadInfo.ids) {
            redirectTable.set(entry, detached ? undefined : entry);
        }
    }
    return redirectTable;
};
export const summarizeBlobManagerState = (redirectTable, attachState) => summarizeV1(redirectTable, attachState);
const summarizeV1 = (redirectTable, attachState) => {
    const storageIds = getStorageIds(redirectTable, attachState);
    // if storageIds is empty, it means we are detached and have only local IDs, or that there are no blobs attached
    const blobIds = storageIds.size > 0 ? [...storageIds] : [...redirectTable.keys()];
    const builder = new SummaryTreeBuilder();
    for (const blobId of blobIds) {
        builder.addAttachment(blobId);
    }
    // Any non-identity entries in the table need to be saved in the summary
    if (redirectTable.size > blobIds.length) {
        builder.addBlob(redirectTableBlobName, 
        // filter out identity entries
        JSON.stringify([...redirectTable.entries()].filter(([localId, storageId]) => localId !== storageId)));
    }
    return builder.getSummaryTree();
};
export const getStorageIds = (redirectTable, attachState) => {
    const ids = new Set(redirectTable.values());
    // If we are detached, we will not have storage IDs, only undefined
    const undefinedValueInTable = ids.delete(undefined);
    // For a detached container, entries are inserted into the redirect table with an undefined storage ID.
    // For an attached container, entries are inserted w/storage ID after the BlobAttach op round-trips.
    assert(!undefinedValueInTable || (attachState === AttachState.Detached && ids.size === 0), 0x382 /* 'redirectTable' must contain only undefined while detached / defined values while attached */);
    return ids;
};
//# sourceMappingURL=blobManagerSnapSum.js.map