/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { assert } from "@fluidframework/core-utils/internal";
import { createIdCompressor, } from "@fluidframework/id-compressor/internal";
import { RevisionTagCodec, TreeStoredSchemaRepository, } from "../core/index.js";
import { createNodeIdentifierManager, fieldBatchCodecBuilder, defaultSchemaPolicy, TreeCompressionStrategy, defaultIncrementalEncodingPolicy, schemaCodecBuilder, } from "../feature-libraries/index.js";
import { combineChunks } from "../feature-libraries/index.js";
import { Breakable, oneFromIterable, } from "../util/index.js";
import { initialize, initializerFromChunk } from "./schematizeTree.js";
import { SchematizingSimpleTreeView } from "./schematizingTreeView.js";
import { buildConfiguredForest, defaultSharedTreeOptions, exportSimpleSchema, } from "./sharedTree.js";
import { createTreeCheckout } from "./treeCheckout.js";
/**
 * Create an uninitialized {@link TreeView} that is not tied to any {@link ITree} instance.
 *
 * @remarks
 * Such a view can never experience collaboration or be persisted to to a Fluid Container.
 *
 * This can be useful for testing, as well as use-cases like working on local files instead of documents stored in some Fluid service.
 * @alpha
 */
export function independentView(config, options) {
    return createIndependentTreeAlpha(options).viewWith(config);
}
/**
 * Create an initialized {@link TreeView} that is not tied to any {@link ITree} instance.
 *
 * @remarks
 * Such a view can never experience collaboration or be persisted to to a Fluid Container.
 *
 * This can be useful for testing, as well as use-cases like working on local files instead of documents stored in some Fluid service.
 * @privateRemarks
 * TODO: Providing an API which generates a {@link ViewableTree} extended with export options from {@link ITreeAlpha} and maybe even branching APIs would likely be better that just exposing a {@link TreeViewAlpha}.
 * @alpha
 */
export function independentInitializedView(config, options, content) {
    return createIndependentTreeAlpha({ ...options, content }).viewWith(config);
}
/**
 * Create a {@link ViewableTree} that is not tied to any Fluid runtimes or services.
 *
 * @remarks
 * Such a tree can never experience collaboration or be persisted to to a Fluid Container.
 *
 * This can be useful for testing, as well as use-cases like working on local files instead of documents stored in some Fluid service.
 *
 * @example
 * ```typescript
 * const tree = createIndependentTreeBeta();
 *
 * const stagedConfig = new TreeViewConfiguration({
 * 	schema: SchemaFactoryAlpha.types([
 * 		SchemaFactory.number,
 * 		SchemaFactoryAlpha.staged(SchemaFactory.string),
 * 	]),
 * });
 * const afterConfig = new TreeViewConfigurationAlpha({
 * 	schema: [SchemaFactory.number, SchemaFactory.string],
 * });
 *
 * // Initialize tree
 * {
 * 	const view = tree.viewWith(stagedConfig);
 * 	view.initialize(1);
 * 	view.dispose();
 * }
 *
 * // Do schema upgrade
 * {
 * 	const view = tree.viewWith(afterConfig);
 * 	view.upgradeSchema();
 * 	view.root = "A";
 * 	view.dispose();
 * }
 *
 * // Can still view tree with staged schema
 * {
 * 	const view = tree.viewWith(stagedConfig);
 * 	assert.equal(view.root, "A");
 * 	view.dispose();
 * }
 * ```
 * @privateRemarks
 * Before stabilizing this as public, consider if we can instead just expose a better way to create regular Fluid service based SharedTrees for tests.
 * Something like https://github.com/microsoft/FluidFramework/pull/25422 might be a better long term stable/public solution.
 * @beta
 */
export function createIndependentTreeBeta(options) {
    return createIndependentTreeAlpha(options);
}
/**
 * Alpha extensions to {@link createIndependentTreeBeta}.
 *
 * @param options - Configuration options for the independent tree.
 * This can be used to create an uninitialized tree, or `content` can be provided to create an initialized tree.
 * If content is provided, the idCompressor is a required part of it: otherwise it is optional and provided at the top level.
 *
 * @privateRemarks
 * TODO: Support more of {@link ITreeAlpha}, including branching APIs to allow for merges.
 * TODO: Better unify this logic with SharedTreeKernel and SharedTreeCore.
 *
 * Before further stabilizing: consider better ways to handle initialized vs uninitialized trees.
 * Perhaps it would be better to not allow initialize here at all, but expose the ability to load compressed tree content and stored schema via ITree or TreeView?
 * If keeping the option here, maybe a separate function of overload would be better? Or maybe flatten ViewContent inline to deduplicate the idCompressor options?
 * @alpha
 */
export function createIndependentTreeAlpha(options) {
    const breaker = new Breakable("independentView");
    const idCompressor = options?.idCompressor ?? options?.content?.idCompressor ?? createIdCompressor();
    const mintRevisionTag = () => idCompressor.generateCompressedId();
    const revisionTagCodec = new RevisionTagCodec(idCompressor);
    // To ensure the forest is in schema when constructed, start it with an empty schema and set the schema repository content later.
    const schemaRepository = new TreeStoredSchemaRepository();
    const forest = buildConfiguredForest(breaker, options?.forest ?? defaultSharedTreeOptions.forest, schemaRepository, idCompressor, defaultIncrementalEncodingPolicy);
    const checkout = createTreeCheckout(idCompressor, mintRevisionTag, revisionTagCodec, {
        forest,
        schema: schemaRepository,
        breaker,
        codecOptions: options,
    });
    if (options?.content !== undefined) {
        const schemaCodec = schemaCodecBuilder.buildDecoder(options);
        const fieldBatchCodec = fieldBatchCodecBuilder.buildDecoder(options);
        const newSchema = schemaCodec.decode(options.content.schema);
        const context = {
            encodeType: TreeCompressionStrategy.Compressed,
            idCompressor,
            originatorId: idCompressor.localSessionId, // Is this right? If so, why is is needed?
            schema: { schema: newSchema, policy: defaultSchemaPolicy },
            // Not a summary blob — this is a synthetic decode of inline content.
            isSummary: false,
        };
        const fieldCursors = fieldBatchCodec.decode(options.content.tree, context);
        assert(fieldCursors.length === 1, 0xa5b /* must have exactly 1 field in batch */);
        const fieldCursor = oneFromIterable(fieldCursors);
        assert(fieldCursor !== undefined, 0xc94 /* expected exactly one field in batch */);
        initialize(checkout, newSchema, initializerFromChunk(checkout, () => combineChunks(checkout.forest.chunkField(fieldCursor))));
    }
    return {
        viewWith(config) {
            const out = new SchematizingSimpleTreeView(checkout, config, createNodeIdentifierManager(idCompressor));
            return out;
        },
        exportVerbose() {
            return checkout.exportVerbose();
        },
        exportSimpleSchema() {
            return exportSimpleSchema(checkout.storedSchema);
        },
    };
}
//# sourceMappingURL=independentView.js.map