/**
 * 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 { UnsupportedOperationError, usingConstantValueSchema, usingModelSchema, customListWithSchema, optionalCustomList, isString, } from '@finos/legend-shared';
import { createModelSchema, custom, deserialize, primitive, serialize, optional, list, raw, } from 'serializr';
import { V1_ExternalFormatData, V1_ModelStoreData, V1_DataElementReference, V1_ModelEmbeddedData, V1_ModelInstanceData, V1_RelationElementsData, V1_RelationRowTestData, V1_RelationElement, } from '../../../model/data/V1_EmbeddedData.js';
import { V1_RelationalCSVData, V1_RelationalCSVDataTable, } from '../../../model/data/V1_RelationalCSVData.js';
import { V1_DataElement } from '../../../model/packageableElements/data/V1_DataElement.js';
import { V1_stereotypePtrModelSchema, V1_taggedValueModelSchema, V1_packageableElementPointerModelSchema, } from './V1_CoreSerializationHelper.js';
import { V1_INTERNAL__UnknownEmbeddedData } from '../../../model/data/V1_INTERNAL__UnknownEmbeddedData.js';
import { V1_PackageableElementPointer } from '../../../model/packageableElements/V1_PackageableElement.js';
import { PackageableElementPointerType } from '../../../../../../../graph/MetaModelConst.js';
export const V1_DATA_ELEMENT_PROTOCOL_TYPE = 'dataElement';
var ModelDataType;
(function (ModelDataType) {
    ModelDataType["MODEL_EMBEDDED_DATA"] = "modelEmbeddedData";
    ModelDataType["MODEL_INSTANCE_DATA"] = "modelInstanceData";
})(ModelDataType || (ModelDataType = {}));
export var V1_EmbeddedDataType;
(function (V1_EmbeddedDataType) {
    V1_EmbeddedDataType["MODEL_STORE_DATA"] = "modelStore";
    V1_EmbeddedDataType["RELATION_ELEMENTS_DATA"] = "relationAccessor";
    V1_EmbeddedDataType["EXTERNAL_FORMAT_DATA"] = "externalFormat";
    V1_EmbeddedDataType["DATA_ELEMENT_REFERENCE"] = "reference";
    V1_EmbeddedDataType["RELATIONAL_DATA"] = "relationalCSVData";
})(V1_EmbeddedDataType || (V1_EmbeddedDataType = {}));
const V1_dataModelDataSchema = (plugins) => createModelSchema(V1_ModelEmbeddedData, {
    _type: usingConstantValueSchema(ModelDataType.MODEL_EMBEDDED_DATA),
    data: custom((val) => V1_serializeEmbeddedDataType(val, plugins), (val) => V1_deserializeEmbeddedDataType(val, plugins)),
    model: primitive(),
});
const V1_dataModelInstanceDataSchema = createModelSchema(V1_ModelInstanceData, {
    _type: usingConstantValueSchema(ModelDataType.MODEL_INSTANCE_DATA),
    instances: raw(),
    model: primitive(),
});
const V1_serializeModelData = (protocol, plugins) => {
    if (protocol instanceof V1_ModelInstanceData) {
        return serialize(V1_dataModelInstanceDataSchema, protocol);
    }
    else if (protocol instanceof V1_ModelEmbeddedData) {
        return serialize(V1_dataModelDataSchema(plugins), protocol);
    }
    throw new UnsupportedOperationError(`Can't serialize model data`, protocol);
};
const V1_deserializeModelData = (json, plugins) => {
    switch (json._type) {
        case ModelDataType.MODEL_EMBEDDED_DATA:
            return deserialize(V1_dataModelDataSchema(plugins), json);
        case ModelDataType.MODEL_INSTANCE_DATA:
            return deserialize(V1_dataModelInstanceDataSchema, json);
        default:
            throw new UnsupportedOperationError(`Can't deserialize assertion status of type '${json._type}'`);
    }
};
export const V1_modelStoreDataModelSchema = (plugins) => createModelSchema(V1_ModelStoreData, {
    _type: usingConstantValueSchema(V1_EmbeddedDataType.MODEL_STORE_DATA),
    modelData: optionalCustomList((value) => V1_serializeModelData(value, plugins), (value) => V1_deserializeModelData(value, plugins)),
});
export const V1_relationRowTestDataModelSchema = createModelSchema(V1_RelationRowTestData, {
    values: list(primitive()),
});
export const V1_relationElementModelSchema = createModelSchema(V1_RelationElement, {
    paths: list(primitive()),
    columns: list(primitive()),
    rows: list(usingModelSchema(V1_relationRowTestDataModelSchema)),
});
export const V1_relationElementsDataModelSchema = createModelSchema(V1_RelationElementsData, {
    _type: usingConstantValueSchema(V1_EmbeddedDataType.RELATION_ELEMENTS_DATA),
    relationElements: list(usingModelSchema(V1_relationElementModelSchema)),
});
export const V1_externalFormatDataModelSchema = createModelSchema(V1_ExternalFormatData, {
    _type: usingConstantValueSchema(V1_EmbeddedDataType.EXTERNAL_FORMAT_DATA),
    contentType: primitive(),
    data: primitive(),
});
const V1_serializeDataElementReferenceValue = (json) => {
    // For backward compatible: see https://github.com/finos/legend-engine/pull/2621
    if (isString(json)) {
        return new V1_PackageableElementPointer(PackageableElementPointerType.DATA, json);
    }
    return deserialize(V1_packageableElementPointerModelSchema, json);
};
export const V1_dataElementReferenceModelSchema = createModelSchema(V1_DataElementReference, {
    _type: usingConstantValueSchema(V1_EmbeddedDataType.DATA_ELEMENT_REFERENCE),
    dataElement: custom((val) => serialize(V1_packageableElementPointerModelSchema, val), (val) => V1_serializeDataElementReferenceValue(val)),
});
const V1_relationalDataTableModelSchema = createModelSchema(V1_RelationalCSVDataTable, {
    schema: optional(primitive()),
    table: primitive(),
    values: primitive(),
});
const V1_relationalDataModelSchema = createModelSchema(V1_RelationalCSVData, {
    _type: usingConstantValueSchema(V1_EmbeddedDataType.RELATIONAL_DATA),
    tables: list(usingModelSchema(V1_relationalDataTableModelSchema)),
});
export function V1_serializeEmbeddedDataType(protocol, plugins) {
    if (protocol instanceof V1_INTERNAL__UnknownEmbeddedData) {
        return protocol.content;
    }
    else if (protocol instanceof V1_ExternalFormatData) {
        return serialize(V1_externalFormatDataModelSchema, protocol);
    }
    else if (protocol instanceof V1_RelationElementsData) {
        return serialize(V1_relationElementsDataModelSchema, protocol);
    }
    else if (protocol instanceof V1_ModelStoreData) {
        return serialize(V1_modelStoreDataModelSchema(plugins), protocol);
    }
    else if (protocol instanceof V1_DataElementReference) {
        return serialize(V1_dataElementReferenceModelSchema, protocol);
    }
    else if (protocol instanceof V1_RelationalCSVData) {
        return serialize(V1_relationalDataModelSchema, protocol);
    }
    const extraEmbeddedDataSerializers = plugins.flatMap((plugin) => plugin.V1_getExtraEmbeddedDataProtocolSerializers?.() ?? []);
    for (const serializer of extraEmbeddedDataSerializers) {
        const embeddedDataProtocolJson = serializer(protocol);
        if (embeddedDataProtocolJson) {
            return embeddedDataProtocolJson;
        }
    }
    throw new UnsupportedOperationError(`Can't serialize embedded data: no compatible serializer available from plugins`, protocol);
}
export function V1_deserializeEmbeddedDataType(json, plugins) {
    switch (json._type) {
        case V1_EmbeddedDataType.EXTERNAL_FORMAT_DATA:
            return deserialize(V1_externalFormatDataModelSchema, json);
        case V1_EmbeddedDataType.MODEL_STORE_DATA:
            return deserialize(V1_modelStoreDataModelSchema(plugins), json);
        case V1_EmbeddedDataType.DATA_ELEMENT_REFERENCE:
            return deserialize(V1_dataElementReferenceModelSchema, json);
        case V1_EmbeddedDataType.RELATIONAL_DATA:
            return deserialize(V1_relationalDataModelSchema, json);
        case V1_EmbeddedDataType.RELATION_ELEMENTS_DATA:
            return deserialize(V1_relationElementsDataModelSchema, json);
        default: {
            const extraEmbeddedDataProtocolDeserializers = plugins.flatMap((plugin) => plugin.V1_getExtraEmbeddedDataProtocolDeserializers?.() ?? []);
            for (const deserializer of extraEmbeddedDataProtocolDeserializers) {
                const protocol = deserializer(json);
                if (protocol) {
                    return protocol;
                }
            }
            // Fall back to create unknown stub if not supported
            const protocol = new V1_INTERNAL__UnknownEmbeddedData();
            protocol.content = json;
            return protocol;
        }
    }
}
export const V1_dataElementModelSchema = (plugins) => createModelSchema(V1_DataElement, {
    _type: usingConstantValueSchema(V1_DATA_ELEMENT_PROTOCOL_TYPE),
    data: custom((val) => V1_serializeEmbeddedDataType(val, plugins), (val) => V1_deserializeEmbeddedDataType(val, plugins)),
    name: primitive(),
    package: primitive(),
    stereotypes: customListWithSchema(V1_stereotypePtrModelSchema, {
        INTERNAL__forceReturnEmptyInTest: true,
    }),
    taggedValues: customListWithSchema(V1_taggedValueModelSchema, {
        INTERNAL__forceReturnEmptyInTest: true,
    }),
});
//# sourceMappingURL=V1_DataElementSerializationHelper.js.map