/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { strict as assert } from "assert";
import { createIdCompressor } from "@fluidframework/id-compressor";
import { runGCTests } from "@fluid-private/test-dds-utils";
import { MockContainerRuntimeFactory, MockFluidDataStoreRuntime, MockStorage, } from "@fluidframework/test-runtime-utils";
import { SharedTree, SharedTreeFactory } from "../../shared-tree/index.js";
import { typeboxValidator } from "../../external-utilities/index.js";
import { SchemaFactory, TreeConfiguration } from "../../simple-tree/index.js";
const builder = new SchemaFactory("test");
class Bar extends builder.object("bar", {
    nestedHandles: builder.array(builder.handle),
}) {
}
class SomeType extends builder.object("foo", {
    handles: builder.array(builder.handle),
    nested: builder.optional(Bar),
    bump: builder.optional(builder.number),
}) {
}
const config = new TreeConfiguration(SomeType, () => ({
    handles: [],
    nested: undefined,
    bump: undefined,
}));
function createConnectedTree(id, runtimeFactory) {
    const dataStoreRuntime = new MockFluidDataStoreRuntime({
        idCompressor: createIdCompressor(),
    });
    const tree = new SharedTree(id, dataStoreRuntime, new SharedTreeFactory().attributes, {}, "SharedTree");
    runtimeFactory.createContainerRuntime(dataStoreRuntime);
    const services = {
        deltaConnection: dataStoreRuntime.createDeltaConnection(),
        objectStorage: new MockStorage(undefined),
    };
    tree.connect(services);
    tree.initializeLocal();
    return tree;
}
function createLocalTree(id) {
    const factory = new SharedTreeFactory({ jsonValidator: typeboxValidator });
    return factory.create(new MockFluidDataStoreRuntime({ idCompressor: createIdCompressor() }), id);
}
describe("Garbage Collection", () => {
    class GCSequenceProvider {
        constructor() {
            this.treeCount = 0;
            this._expectedRoutes = [];
            this.containerRuntimeFactory = new MockContainerRuntimeFactory();
            this.tree1 = createConnectedTree("tree1", this.containerRuntimeFactory);
            this.tree2 = createConnectedTree("tree2", this.containerRuntimeFactory);
            this.tree1View = this.tree1.schematize(config).root;
        }
        get sharedObject() {
            return this.tree2;
        }
        get expectedOutboundRoutes() {
            return this._expectedRoutes;
        }
        async addOutboundRoutes() {
            const subtree1 = createLocalTree(`tree-${++this.treeCount}`);
            const subtree2 = createLocalTree(`tree-${++this.treeCount}`);
            this.tree1View.handles.insertAtEnd(subtree1.handle, subtree2.handle);
            this._expectedRoutes.push(subtree1.handle.absolutePath, subtree2.handle.absolutePath);
            this.containerRuntimeFactory.processAllMessages();
        }
        async deleteOutboundRoutes() {
            assert(this.tree1View.handles.length > 0, "Route must be added before deleting");
            const lastElementIndex = this.tree1View.handles.length - 1;
            // Get the handles that were last added.
            const deletedHandles = this.tree1View.handles;
            // Get the routes of the handles.
            const deletedHandleRoutes = Array.from(deletedHandles, (handle) => handle.absolutePath);
            // Remove the last added handles.
            this.tree1View.handles.removeRange(0, lastElementIndex + 1);
            // Remove the deleted routes from expected routes.
            const skip = true;
            // TODO: ADO#4700 Currently deleted handles will never leave
            // the summary of a tree because they will be persisted forever
            // in the repair data. Eventually, repair data should be
            // automatically cleaned up after some condition, and this test
            // should be updated to hit that condition.
            if (!skip) {
                this._expectedRoutes = this._expectedRoutes.filter((route) => !deletedHandleRoutes.includes(route));
            }
            this.containerRuntimeFactory.processAllMessages();
            // Send an op so the minimum sequence number moves past the segment which got removed.
            // This will ensure that the segment is not part of the summary anymore.
            this.tree1View.bump = 0;
            this.containerRuntimeFactory.processAllMessages();
        }
        async addNestedHandles() {
            const subtree1 = createLocalTree(`tree-${++this.treeCount}`);
            const subtree2 = createLocalTree(`tree-${++this.treeCount}`);
            this.tree1View.nested = new Bar({
                nestedHandles: [subtree1.handle, subtree2.handle],
            });
            this._expectedRoutes.push(subtree1.handle.absolutePath, subtree2.handle.absolutePath);
            this.containerRuntimeFactory.processAllMessages();
        }
    }
    runGCTests(GCSequenceProvider);
});
//# sourceMappingURL=gc.spec.js.map