/*!
 * 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 { UsageError } from "@fluidframework/telemetry-utils/internal";
import { getKernel, TreeBeta, tryGetSchema, createFromCursor, createFromInsertable, cursorFromInsertable, FieldKind, normalizeFieldSchema, conciseFromCursor, applySchemaToParserOptions, cursorFromVerbose, verboseFromCursor, toStoredSchema, extractPersistedSchema, TreeViewConfiguration, } from "../simple-tree/index.js";
import { fail } from "../util/index.js";
import { noopValidator } from "../codec/index.js";
import { cursorForMapTreeField, defaultSchemaPolicy, isTreeValue, makeFieldBatchCodec, mapTreeFromCursor, TreeCompressionStrategy, } from "../feature-libraries/index.js";
import { independentInitializedView } from "./independentView.js";
import { SchematizingSimpleTreeView, ViewSlot } from "./schematizingTreeView.js";
/**
 * Extensions to {@link Tree} and {@link TreeBeta} which are not yet stable.
 * @sealed @alpha
 */
export const TreeAlpha = {
    branch(node) {
        const kernel = getKernel(node);
        if (!kernel.isHydrated()) {
            return undefined;
        }
        const view = kernel.anchorNode.anchorSet.slots.get(ViewSlot);
        assert(view instanceof SchematizingSimpleTreeView, 0xa5c /* Unexpected view implementation */);
        return view;
    },
    create: createFromInsertable,
    importConcise(schema, data) {
        return createFromInsertable(schema, data);
    },
    importVerbose(schema, data, options) {
        const config = {
            valueConverter: (input) => {
                return input;
            },
            ...options,
        };
        // Create a config which is standalone, and thus can be used without having to refer back to the schema.
        const schemalessConfig = applySchemaToParserOptions(schema, config);
        if (data === undefined) {
            const field = normalizeFieldSchema(schema);
            if (field.kind !== FieldKind.Optional) {
                throw new UsageError("undefined provided for non-optional field.");
            }
            return undefined;
        }
        const cursor = cursorFromVerbose(data, schemalessConfig);
        return createFromCursor(schema, cursor);
    },
    exportConcise(node, options) {
        const config = {
            valueConverter(handle) {
                return handle;
            },
            ...options,
        };
        const cursor = borrowCursorFromTreeNodeOrValue(node);
        return conciseFromCursor(cursor, tryGetSchema(node) ?? fail("invalid input"), config);
    },
    exportVerbose(node, options) {
        const config = {
            valueConverter(handle) {
                return handle;
            },
            ...options,
        };
        const cursor = borrowCursorFromTreeNodeOrValue(node);
        return verboseFromCursor(cursor, tryGetSchema(node) ?? fail("invalid input"), config);
    },
    exportCompressed(node, options) {
        const schema = tryGetSchema(node) ?? fail("invalid input");
        const format = versionToFormat[options.oldestCompatibleClient];
        const codec = makeFieldBatchCodec({ jsonValidator: noopValidator }, format);
        const cursor = borrowFieldCursorFromTreeNodeOrValue(node);
        const batch = [cursor];
        // If none provided, create a compressor which will not compress anything.
        const idCompressor = options.idCompressor ?? createIdCompressor();
        const context = {
            encodeType: TreeCompressionStrategy.Compressed,
            idCompressor,
            originatorId: idCompressor.localSessionId, // TODO: Why is this needed?
            schema: { schema: toStoredSchema(schema), policy: defaultSchemaPolicy },
        };
        const result = codec.encode(batch, context);
        return result;
    },
    importCompressed(schema, compressedData, options) {
        const content = {
            schema: extractPersistedSchema(schema),
            tree: compressedData,
            idCompressor: options.idCompressor ?? createIdCompressor(),
        };
        const config = new TreeViewConfiguration({ schema });
        const view = independentInitializedView(config, options, content);
        return TreeBeta.clone(view.root);
    },
};
function borrowCursorFromTreeNodeOrValue(node) {
    if (isTreeValue(node)) {
        return cursorFromInsertable(tryGetSchema(node) ?? fail("missing schema"), node);
    }
    const kernel = getKernel(node);
    const cursor = kernel.getOrCreateInnerNode().borrowCursor();
    return cursor;
}
function borrowFieldCursorFromTreeNodeOrValue(node) {
    const cursor = borrowCursorFromTreeNodeOrValue(node);
    // TODO: avoid copy
    const mapTree = mapTreeFromCursor(cursor);
    return cursorForMapTreeField([mapTree]);
}
const versionToFormat = {
    v2_0: 1,
    v2_1: 1,
    v2_2: 1,
    v2_3: 1,
};
//# sourceMappingURL=treeApiAlpha.js.map