/**
 * Copyright (c) 2020-present, Goldman Sachs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { list, createModelSchema, primitive, custom, optional, serialize, deserialize, object, } from 'serializr';
import { usingConstantValueSchema, UnsupportedOperationError, assertErrorThrown, usingModelSchema, guaranteeNonNullable, } from '@finos/legend-shared';
import { V1_PureModelContextData } from '../../model/context/V1_PureModelContextData.js';
import { V1_PureModelContextPointer } from '../../model/context/V1_PureModelContextPointer.js';
import { V1_serializePackageableElement, V1_deserializePackageableElement, } from '../../transformation/pureProtocol/V1_PackageableElementSerialization.js';
import { V1_PureModelContextComposite } from '../../model/context/V1_PureModelContextComposite.js';
import { V1_Protocol } from '../../model/V1_Protocol.js';
import { V1_LegendSDLC } from '../../model/context/V1_SDLC.js';
import { V1_packageableElementPointerModelSchema } from '../../transformation/pureProtocol/serializationHelpers/V1_CoreSerializationHelper.js';
import { GraphDataDeserializationError } from '../../../../../../graph-manager/GraphManagerUtils.js';
import { V1_PureModelContextText } from '../../model/context/V1_PureModelContextText.js';
import { V1_PureModelContextCombination } from '../../model/context/V1_PureModelContextCombination.js';
var V1_SDLCType;
(function (V1_SDLCType) {
    V1_SDLCType["ALLOY"] = "alloy";
})(V1_SDLCType || (V1_SDLCType = {}));
export var V1_PureModelContextType;
(function (V1_PureModelContextType) {
    V1_PureModelContextType["DATA"] = "data";
    V1_PureModelContextType["POINTER"] = "pointer";
    V1_PureModelContextType["COMPOSITE"] = "composite";
    V1_PureModelContextType["TEXT"] = "text";
    V1_PureModelContextType["COMBINATION"] = "combination";
})(V1_PureModelContextType || (V1_PureModelContextType = {}));
export const V1_entitiesToPureModelContextData = async (entities, graph, plugins, subtypeInfo, classifierPathMappingMap, 
/**
 * FIXME: to be deleted when most users have migrated to using full function signature as function name
 * Currently, SDLC store many functions in legacy form (entity path does
 * not contain full function signature). However, since they store function
 * entity in text, when they parse the content to return JSON for entity
 * content, the content is then updated to have proper `name` for function
 * entities, this means that there's now a mismatch in the path constructed
 * from entity content and the entity path, which is a contract that SDLC
 * should maintain but currently not because of this change
 * See https://github.com/finos/legend-sdlc/pull/515
 *
 * For that reason, during this migration, we want to respect entity path
 * instead of the path constructed from entity content to properly
 * reflect the renaming of function in local changes.
 */
TEMPORARY__entityPathIndex) => {
    try {
        if (entities?.length) {
            const entityToElement = (entity) => {
                const element = V1_deserializePackageableElement(entity.content, plugins, subtypeInfo, classifierPathMappingMap, entity.classifierPath);
                TEMPORARY__entityPathIndex?.set(element.path, entity.path);
                return element;
            };
            // Process entities in batches to avoid per-element setTimeout overhead.
            // Each batch yields to the event loop to keep the UI responsive.
            const DESERIALIZATION_BATCH_SIZE = 100;
            const results = [];
            for (let i = 0; i < entities.length; i += DESERIALIZATION_BATCH_SIZE) {
                if (i > 0) {
                    await new Promise((resolve) => setTimeout(resolve, 0));
                }
                const end = Math.min(i + DESERIALIZATION_BATCH_SIZE, entities.length);
                for (let j = i; j < end; j++) {
                    // NOTE: here we skip the check for classifier path, so there could be cases
                    // where the classifier path is different from the actua element protocol path
                    // we might need to do validation here. This can happen when the classifier
                    // path is changed in the backend. If we are to check for this, we might consider
                    // not throwing error but quitely print out warnings about elements that would not
                    // be built.
                    results.push(entityToElement(guaranteeNonNullable(entities[j])));
                }
            }
            graph.elements = results;
        }
    }
    catch (error) {
        assertErrorThrown(error);
        // wrap all de-serializer error so we can handle them downstream
        throw new GraphDataDeserializationError(error);
    }
};
export const V1_legendSDLCSerializationModelSchema = createModelSchema(V1_LegendSDLC, {
    _type: usingConstantValueSchema(V1_SDLCType.ALLOY),
    baseVersion: optional(primitive()),
    version: primitive(),
    groupId: primitive(),
    artifactId: primitive(),
    packageableElementPointers: list(usingModelSchema(V1_packageableElementPointerModelSchema)),
});
const V1_pureModelContextTextSchema = createModelSchema(V1_PureModelContextText, {
    _type: usingConstantValueSchema(V1_PureModelContextType.TEXT),
    serializer: usingModelSchema(V1_Protocol.serialization.schema),
    code: optional(primitive()),
});
const V1_pureModelContextPointerModelSchema = createModelSchema(V1_PureModelContextPointer, {
    _type: usingConstantValueSchema(V1_PureModelContextType.POINTER),
    serializer: optional(usingModelSchema(V1_Protocol.serialization.schema)),
    sdlcInfo: usingModelSchema(V1_legendSDLCSerializationModelSchema),
});
const V1_pureModelContextCompositeModelSchema = createModelSchema(V1_PureModelContextComposite, {
    _type: usingConstantValueSchema(V1_PureModelContextType.COMPOSITE),
    serializer: usingModelSchema(V1_Protocol.serialization.schema),
    // TODO: use `V1_pureModelContextDataPropSchema`
    data: object(V1_PureModelContextData),
    pointer: usingModelSchema(V1_pureModelContextPointerModelSchema),
});
const V1_pureModelContextCombinationModelSchema = createModelSchema(V1_PureModelContextCombination, {
    _type: usingConstantValueSchema(V1_PureModelContextType.COMBINATION),
    serializer: usingModelSchema(V1_Protocol.serialization.schema),
    contexts: list(custom((element) => 
    // eslint-disable-next-line @typescript-eslint/no-use-before-define
    V1_serializePureModelContext(element), (element) => 
    // eslint-disable-next-line @typescript-eslint/no-use-before-define
    V1_deserializePureModelContext(element))),
});
export const V1_setupPureModelContextDataSerialization = (plugins, subtypeInfo, classifierPathMappingMap) => {
    createModelSchema(V1_PureModelContextData, {
        _type: usingConstantValueSchema(V1_PureModelContextType.DATA),
        origin: usingModelSchema(V1_pureModelContextPointerModelSchema),
        elements: list(custom((element) => V1_serializePackageableElement(element, plugins), (element) => V1_deserializePackageableElement(element, plugins, subtypeInfo, classifierPathMappingMap))),
        serializer: usingModelSchema(V1_Protocol.serialization.schema),
    });
};
export const V1_deserializePureModelContextData = (json) => deserialize(V1_PureModelContextData, json);
export const V1_serializePureModelContextData = (protocol) => serialize(V1_PureModelContextData, protocol);
export const V1_serializePureModelContext = (pureModelContext) => {
    if (pureModelContext instanceof V1_PureModelContextPointer) {
        return serialize(V1_pureModelContextPointerModelSchema, pureModelContext);
    }
    else if (pureModelContext instanceof V1_PureModelContextData) {
        const rawPMCD = V1_serializePureModelContextData(pureModelContext);
        if (pureModelContext.INTERNAL__rawDependencyEntities?.length) {
            rawPMCD.elements = [
                ...rawPMCD.elements,
                ...pureModelContext.INTERNAL__rawDependencyEntities.map((e) => e.content),
            ];
        }
        return rawPMCD;
    }
    else if (pureModelContext instanceof V1_PureModelContextComposite) {
        return serialize(V1_pureModelContextCompositeModelSchema, pureModelContext);
    }
    else if (pureModelContext instanceof V1_PureModelContextText) {
        return serialize(V1_pureModelContextTextSchema, pureModelContext);
    }
    else if (pureModelContext instanceof V1_PureModelContextCombination) {
        return serialize(V1_pureModelContextCombinationModelSchema, pureModelContext);
    }
    throw new UnsupportedOperationError(`Can't serialize Pure model context`, pureModelContext);
};
export const V1_deserializePureModelContext = (json) => {
    switch (json._type) {
        case V1_PureModelContextType.POINTER:
            return deserialize(V1_pureModelContextPointerModelSchema, json);
        case V1_PureModelContextType.DATA:
            return V1_deserializePureModelContextData(json);
        case V1_PureModelContextType.COMPOSITE:
            return deserialize(V1_pureModelContextCompositeModelSchema, json);
        case V1_PureModelContextType.TEXT:
            return deserialize(V1_pureModelContextTextSchema, json);
        case V1_PureModelContextType.COMBINATION:
            return deserialize(V1_pureModelContextCombinationModelSchema, json);
        default:
            throw new UnsupportedOperationError(`Can't deserialize Pure model context`, json);
    }
};
export const V1_pureModelContextDataPropSchema = custom((val) => V1_serializePureModelContextData(val), (val) => V1_deserializePureModelContextData(val));
export const V1_pureModelContextPropSchema = custom((val) => V1_serializePureModelContext(val), (val) => V1_deserializePureModelContext(val));
//# sourceMappingURL=V1_PureProtocolSerialization.js.map