/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
import { Type } from "@sinclair/typebox";
import { RevisionTagSchema } from "../../core";
import { ChangesetLocalIdSchema, EncodedChangeAtomId, } from "../modular-schema";
// TODO:AB#4259 Decouple types used for sequence-field's in-memory representation from their encoded variants.
// Currently, types in this file are largely used for both.
// See for example `Revive` whose type uses ITreeCursorSynchronous,
// but the schema for the serialized type uses ProtoNode (which is the result of serializing that cursor).
const noAdditionalProps = { additionalProperties: false };
export const ProtoNode = Type.Any();
export const CellCount = Type.Number();
/**
 * Left undefined for terseness.
 */
export const NoopMarkType = undefined;
export const MoveId = ChangesetLocalIdSchema;
export const HasMoveId = Type.Object({ id: MoveId });
// Boolean encodings can use this alternative to save space for frequently false values.
const OptionalTrue = Type.Optional(Type.Literal(true));
export const LineageEvent = Type.Object({
    revision: Type.Readonly(RevisionTagSchema),
    id: Type.Readonly(ChangesetLocalIdSchema),
    count: Type.Readonly(Type.Number()),
    offset: Type.Readonly(Type.Number()),
}, noAdditionalProps);
export const HasLineage = Type.Object({ lineage: Type.Optional(Type.Array(LineageEvent)) });
export const CellId = Type.Composite([EncodedChangeAtomId, HasLineage]);
export const HasMarkFields = (tNodeChange) => Type.Object({
    cellId: Type.Optional(CellId),
    changes: Type.Optional(tNodeChange),
    count: CellCount,
});
export const HasReattachFields = (tNodeChange) => Type.Composite([
    Type.Object({
        inverseOf: Type.Optional(RevisionTagSchema),
    }),
    HasMarkFields(tNodeChange),
]);
export const NoopMark = (tNodeChange) => Type.Composite([HasMarkFields(tNodeChange)], noAdditionalProps);
export const HasRevisionTag = Type.Object({ revision: Type.Optional(RevisionTagSchema) });
export const Transient = Type.Object({ detachedBy: EncodedChangeAtomId });
export const CanBeTransient = Type.Partial(Transient);
export const Insert = (tNodeChange) => Type.Composite([
    HasMarkFields(tNodeChange),
    HasRevisionTag,
    CanBeTransient,
    Type.Object({
        type: Type.Literal("Insert"),
        content: Type.Array(ProtoNode),
    }),
], noAdditionalProps);
export const MoveIn = Type.Composite([
    HasMoveId,
    HasMarkFields(Type.Undefined()),
    HasRevisionTag,
    Type.Object({
        type: Type.Literal("MoveIn"),
        isSrcConflicted: OptionalTrue,
    }),
], noAdditionalProps);
export const Delete = (tNodeChange) => Type.Composite([
    HasRevisionTag,
    HasMarkFields(tNodeChange),
    Type.Object({
        type: Type.Literal("Delete"),
        id: ChangesetLocalIdSchema,
    }),
], noAdditionalProps);
export const MoveOut = (tNodeChange) => Type.Composite([
    HasRevisionTag,
    HasMoveId,
    HasMarkFields(tNodeChange),
    Type.Object({
        type: Type.Literal("MoveOut"),
    }),
], noAdditionalProps);
export const Revive = (tNodeChange) => Type.Composite([
    HasReattachFields(tNodeChange),
    HasRevisionTag,
    CanBeTransient,
    Type.Object({
        type: Type.Literal("Revive"),
        content: Type.Array(ProtoNode),
    }),
], noAdditionalProps);
export const ReturnTo = Type.Composite([
    HasReattachFields(Type.Undefined()),
    HasRevisionTag,
    HasMoveId,
    Type.Object({
        type: Type.Literal("ReturnTo"),
        isSrcConflicted: OptionalTrue,
    }),
], noAdditionalProps);
export const ReturnFrom = (tNodeChange) => Type.Composite([
    HasRevisionTag,
    HasMoveId,
    HasMarkFields(tNodeChange),
    Type.Object({
        type: Type.Literal("ReturnFrom"),
        isDstConflicted: OptionalTrue,
    }),
], noAdditionalProps);
export const NewAttach = (tNodeChange) => Type.Union([Insert(tNodeChange), MoveIn]);
export const Reattach = (tNodeChange) => Type.Union([Revive(tNodeChange), ReturnTo]);
export const Attach = (tNodeChange) => Type.Union([NewAttach(tNodeChange), Reattach(tNodeChange)]);
export const Detach = (tNodeChange) => Type.Union([Delete(tNodeChange), MoveOut(tNodeChange), ReturnFrom(tNodeChange)]);
export const Mark = (tNodeChange) => Type.Union([NoopMark(tNodeChange), Attach(tNodeChange), Detach(tNodeChange)]);
export const Changeset = (tNodeChange) => Type.Array(Mark(tNodeChange));
//# sourceMappingURL=format.js.map