"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.getStorageIds = exports.summarizeBlobManagerState = exports.toRedirectTable = exports.loadBlobManagerLoadInfo = exports.blobsTreeName = exports.redirectTableBlobName = void 0;
const internal_1 = require("@fluidframework/container-definitions/internal");
const internal_2 = require("@fluidframework/core-utils/internal");
const internal_3 = require("@fluidframework/driver-utils/internal");
const internal_4 = require("@fluidframework/runtime-utils/internal");
exports.redirectTableBlobName = ".redirectTable";
/**
 * @internal
 */
exports.blobsTreeName = ".blobs";
/**
 * Reads blobs needed to load BlobManager from storage.
 *
 */
const loadBlobManagerLoadInfo = async (context) => loadV1(context);
exports.loadBlobManagerLoadInfo = loadBlobManagerLoadInfo;
const loadV1 = async (context) => {
    const blobsTree = context.baseSnapshot?.trees[exports.blobsTreeName];
    if (!blobsTree) {
        return {};
    }
    let redirectTableEntries = [];
    const tableId = blobsTree.blobs[exports.redirectTableBlobName];
    if (tableId) {
        redirectTableEntries = await (0, internal_3.readAndParse)(context.storage, tableId);
    }
    const ids = Object.entries(blobsTree.blobs)
        .filter(([k, _]) => k !== exports.redirectTableBlobName)
        .map(([_, v]) => v);
    return { ids, redirectTable: redirectTableEntries };
};
const toRedirectTable = (snapshot, logger, attachState) => {
    logger.sendTelemetryEvent({
        eventName: "AttachmentBlobsLoaded",
        count: snapshot.ids?.length ?? 0,
        redirectTable: snapshot.redirectTable?.length,
    });
    const redirectTable = new Map(snapshot.redirectTable);
    const detached = attachState !== internal_1.AttachState.Attached;
    if (snapshot.ids) {
        // If we are detached, we don't have storage IDs yet, so set to undefined
        // Otherwise, set identity (id -> id) entries.
        snapshot.ids.forEach((entry) => redirectTable.set(entry, detached ? undefined : entry));
    }
    return redirectTable;
};
exports.toRedirectTable = toRedirectTable;
const summarizeBlobManagerState = (redirectTable, attachState) => summarizeV1(redirectTable, attachState);
exports.summarizeBlobManagerState = summarizeBlobManagerState;
const summarizeV1 = (redirectTable, attachState) => {
    const storageIds = (0, exports.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 ? Array.from(storageIds) : Array.from(redirectTable.keys());
    const builder = new internal_4.SummaryTreeBuilder();
    blobIds.forEach((blobId) => {
        builder.addAttachment(blobId);
    });
    // Any non-identity entries in the table need to be saved in the summary
    if (redirectTable.size > blobIds.length) {
        builder.addBlob(exports.redirectTableBlobName, 
        // filter out identity entries
        JSON.stringify(Array.from(redirectTable.entries()).filter(([localId, storageId]) => localId !== storageId)));
    }
    return builder.getSummaryTree();
};
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.
    (0, internal_2.assert)(!undefinedValueInTable || (attachState === internal_1.AttachState.Detached && ids.size === 0), 0x382 /* 'redirectTable' must contain only undefined while detached / defined values while attached */);
    return ids;
};
exports.getStorageIds = getStorageIds;
//# sourceMappingURL=blobManagerSnapSum.js.map