/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { fail } from "@fluidframework/core-utils/internal";
import { lowestMinVersionForCollab } from "@fluidframework/runtime-utils/internal";
import { ClientVersionDispatchingCodecBuilder, FluidClientVersion, } from "../../codec/index.js";
import { SchemaFormatVersion, decodeFieldSchema, encodeFieldSchemaV1, encodeFieldSchemaV2, storedSchemaDecodeDispatcher, } from "../../core/index.js";
import { brand } from "../../util/index.js";
import { Format as FormatV1 } from "./formatV1.js";
import { Format as FormatV2 } from "./formatV2.js";
function encodeRepoV1(repo) {
    const nodeSchema = encodeNodeSchema(repo, (schema) => schema.encodeV1());
    const rootFieldSchema = encodeFieldSchemaV1(repo.rootFieldSchema);
    return {
        version: SchemaFormatVersion.v1,
        nodes: nodeSchema,
        root: rootFieldSchema,
    };
}
function encodeRepoV2(repo) {
    const nodeSchema = encodeNodeSchema(repo, (schema) => schema.encodeV2());
    const rootFieldSchema = encodeFieldSchemaV2(repo.rootFieldSchema);
    return {
        version: SchemaFormatVersion.v2,
        nodes: nodeSchema,
        root: rootFieldSchema,
    };
}
/**
 * Shared logic for encoding node schemas.
 * @param repo - The stored schema to encode.
 * @param encodeValue - A function which encodes a single node schema.
 * @returns The encoded node schema.
 */
function encodeNodeSchema(repo, encodeValue) {
    const nodeSchema = Object.create(null);
    for (const name of [...repo.nodeSchema.keys()].sort()) {
        const schema = repo.nodeSchema.get(name) ?? fail(0xb28 /* missing schema */);
        Object.defineProperty(nodeSchema, name, {
            enumerable: true,
            configurable: true,
            writable: true,
            value: encodeValue(schema),
        });
    }
    return nodeSchema;
}
function decodeV1(f) {
    const nodeSchema = new Map();
    for (const [key, schema] of Object.entries(f.nodes)) {
        const storedSchemaDecoder = storedSchemaDecodeDispatcher.dispatch(schema);
        // No metadata in v1, so pass undefined
        nodeSchema.set(brand(key), storedSchemaDecoder(undefined));
    }
    return {
        rootFieldSchema: decodeFieldSchema(f.root),
        nodeSchema,
    };
}
function decodeV2(f) {
    const nodeSchema = new Map();
    for (const [key, schema] of Object.entries(f.nodes)) {
        const storedSchemaDecoder = storedSchemaDecodeDispatcher.dispatch(schema.kind);
        // Pass in the node metadata
        nodeSchema.set(brand(key), storedSchemaDecoder(schema.metadata));
    }
    return {
        rootFieldSchema: decodeFieldSchema(f.root),
        nodeSchema,
    };
}
/**
 * Creates a codec which performs synchronous monolithic encoding of schema content.
 */
export const schemaCodecBuilder = ClientVersionDispatchingCodecBuilder.build("Schema", [
    {
        minVersionForCollab: lowestMinVersionForCollab,
        formatVersion: SchemaFormatVersion.v1,
        codec: {
            encode: (data) => encodeRepoV1(data),
            decode: (data) => decodeV1(data),
            schema: FormatV1,
        },
    },
    {
        minVersionForCollab: FluidClientVersion.v2_43,
        formatVersion: SchemaFormatVersion.v2,
        codec: {
            encode: (data) => encodeRepoV2(data),
            decode: (data) => decodeV2(data),
            schema: FormatV2,
        },
    },
]);
//# sourceMappingURL=codec.js.map