/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { fail } from "@fluidframework/core-utils/internal";
import { DiscriminatedUnionDispatcher, makeCodecFamily, withSchemaValidation, } from "../codec/index.js";
import { SchemaFormatVersion, } from "../core/index.js";
import { defaultSchemaPolicy, getCodecTreeForModularChangeFormat, getCodecTreeForSchemaChangeFormat, makeSchemaChangeCodecs, } from "../feature-libraries/index.js";
import { brand, } from "../util/index.js";
import { EncodedSharedTreeChange, } from "./sharedTreeChangeFormat.js";
export function makeSharedTreeChangeCodecFamily(modularChangeCodecFamily, options) {
    const schemaChangeCodecs = makeSchemaChangeCodecs(options);
    const versions = Array.from(dependenciesForChangeFormat.entries()).map(([format, { modularChange, schemaChange }]) => [
        format,
        makeSharedTreeChangeCodec(modularChangeCodecFamily.resolve(modularChange).json, schemaChangeCodecs.resolve(schemaChange).json, options),
    ]);
    return makeCodecFamily(versions);
}
/**
 * Defines for each SharedTree change format the corresponding dependent formats to use.
 * This is an arbitrary mapping that is injected in the SharedTree change codec.
 * Once an entry is defined and used in production, it cannot be changed.
 * This is because the format for the dependent formats are not explicitly versioned.
 */
export const dependenciesForChangeFormat = new Map([
    [brand(3), { modularChange: brand(3), schemaChange: brand(SchemaFormatVersion.v1) }],
    [brand(4), { modularChange: brand(4), schemaChange: brand(SchemaFormatVersion.v1) }],
    [brand(101), { modularChange: brand(101), schemaChange: brand(SchemaFormatVersion.v1) }],
]);
export function getCodecTreeForChangeFormat(version, clientVersion) {
    const { modularChange, schemaChange } = dependenciesForChangeFormat.get(version) ?? fail(0xc78 /* Unknown change format */);
    return {
        name: "SharedTreeChange",
        version,
        children: [
            getCodecTreeForModularChangeFormat(modularChange),
            getCodecTreeForSchemaChangeFormat(schemaChange, clientVersion),
        ],
    };
}
function makeSharedTreeChangeCodec(modularChangeCodec, schemaChangeCodec, codecOptions) {
    const decoderLibrary = new DiscriminatedUnionDispatcher({
        data(encoded, context) {
            return {
                type: "data",
                innerChange: modularChangeCodec.decode(encoded, context),
            };
        },
        schema(encoded) {
            return {
                type: "schema",
                innerChange: schemaChangeCodec.decode(encoded),
            };
        },
    });
    return withSchemaValidation(EncodedSharedTreeChange, {
        encode: (change, context) => {
            const changes = [];
            let updatedSchema;
            for (const decodedChange of change.changes) {
                if (decodedChange.type === "data") {
                    const schemaAndPolicy = updatedSchema !== undefined
                        ? {
                            policy: context.schema !== undefined
                                ? context.schema.policy
                                : defaultSchemaPolicy,
                            schema: updatedSchema,
                        }
                        : context.schema;
                    changes.push({
                        data: modularChangeCodec.encode(decodedChange.innerChange, {
                            originatorId: context.originatorId,
                            schema: schemaAndPolicy,
                            idCompressor: context.idCompressor,
                            revision: context.revision,
                        }),
                    });
                }
                else if (decodedChange.type === "schema") {
                    changes.push({
                        schema: schemaChangeCodec.encode(decodedChange.innerChange),
                    });
                    updatedSchema = decodedChange.innerChange.schema.new;
                }
            }
            return changes;
        },
        decode: (encodedChange, context) => {
            const changes = [];
            for (const subChange of encodedChange) {
                changes.push(decoderLibrary.dispatch(subChange, context));
            }
            return { changes };
        },
    }, codecOptions.jsonValidator);
}
//# sourceMappingURL=sharedTreeChangeCodecs.js.map